Skip to content

Commit f37b3bf

Browse files
authored
Merge pull request #87 from blocknotes/internal-improvements-5
Internal improvements 5
2 parents b22249e + fdf259f commit f37b3bf

8 files changed

Lines changed: 53 additions & 40 deletions

File tree

active_storage_db.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
$:.push File.expand_path("lib", __dir__)
3+
$LOAD_PATH.unshift File.expand_path("lib", __dir__)
44

55
# Maintain your gem's version:
66
require "active_storage_db/version"

app/controllers/active_storage_db/files_controller.rb

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ def show
1717
def update
1818
if (token = decode_verified_token)
1919
file_uploaded = upload_file(token)
20-
head(file_uploaded ? :no_content : unprocessable)
20+
head(file_uploaded ? :no_content : ActiveStorageDB::UNPROCESSABLE_STATUS)
2121
else
2222
head(:not_found)
2323
end
2424
rescue ActiveStorage::IntegrityError
25-
head(unprocessable)
25+
head(ActiveStorageDB::UNPROCESSABLE_STATUS)
2626
end
2727

2828
private
@@ -60,13 +60,5 @@ def upload_file(token) # rubocop:disable Naming/PredicateMethod
6060
db_service.upload(token[:key], request.body, checksum: token[:checksum])
6161
true
6262
end
63-
64-
def unprocessable
65-
if Rails::VERSION::MAJOR > 7 || (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1)
66-
:unprocessable_content
67-
else
68-
:unprocessable_entity
69-
end
70-
end
7163
end
7264
end

lib/active_storage/service/db_service.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,17 @@ class Service::DBService < Service
2222

2323
def initialize(public: false, **)
2424
@chunk_size = [ENV.fetch("ASDB_CHUNK_SIZE") { 1.megabytes }.to_i, MINIMUM_CHUNK_SIZE].max
25+
@max_size = ENV.fetch("ASDB_MAX_FILE_SIZE", nil)&.to_i
2526
@public = public
2627
end
2728

2829
def upload(key, io, checksum: nil, **)
2930
instrument :upload, key: key, checksum: checksum do
3031
data = io.read
32+
if @max_size && data.bytesize > @max_size
33+
raise ArgumentError, "File size exceeds the maximum allowed size of #{@max_size} bytes"
34+
end
35+
3136
if checksum
3237
digest = Digest::MD5.base64digest(data)
3338
raise ActiveStorage::IntegrityError unless digest == checksum
@@ -50,6 +55,8 @@ def download(key, &block)
5055

5156
def download_chunk(key, range)
5257
instrument :download_chunk, key: key, range: range do
58+
# NOTE: from/size are derived from Range#begin and Range#size (always integers),
59+
# so string interpolation into SQL is safe here.
5360
from = range.begin + 1
5461
size = range.size
5562
args = adapter_sqlserver? || adapter_sqlite? ? "data, #{from}, #{size}" : "data FROM #{from} FOR #{size}"
@@ -81,7 +88,7 @@ def delete_prefixed(prefix)
8188
def exist?(key)
8289
instrument :exist, key: key do |payload|
8390
comment = "DBService#exist?"
84-
result = ::ActiveStorageDB::File.annotate(comment).where(ref: key).exists?
91+
result = ::ActiveStorageDB::File.annotate(comment).exists?(ref: key)
8592
payload[:exist] = result
8693
result
8794
end
@@ -172,7 +179,7 @@ def retrieve_file(key)
172179
def object_for(key, fields: nil)
173180
comment = "DBService#object_for"
174181
scope = ::ActiveStorageDB::File.annotate(comment)
175-
scope = scope.select(*fields) if fields
182+
scope = scope.select(fields) if fields
176183
scope.find_by(ref: key)
177184
end
178185

lib/active_storage/service/db_service_rails70.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def compose(source_keys, destination_key, **)
66
buffer = nil
77
comment = "DBService#compose"
88
source_keys.each do |source_key|
9-
record = ::ActiveStorageDB::File.annotate(comment).find_by(ref: source_key)
9+
record = ::ActiveStorageDB::File.annotate(comment).select(:data).find_by(ref: source_key)
1010
raise ActiveStorage::FileNotFoundError unless record
1111

1212
if buffer

lib/active_storage_db/engine.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# frozen_string_literal: true
22

33
module ActiveStorageDB
4+
# :nocov:
5+
UNPROCESSABLE_STATUS = if Rails::VERSION::MAJOR > 7 || (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1)
6+
:unprocessable_content
7+
else
8+
:unprocessable_entity
9+
end
10+
# :nocov:
11+
412
class Engine < ::Rails::Engine
513
isolate_namespace ActiveStorageDB
614
end

lib/tasks/active_storage_db_tasks.rake

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,30 @@ module ActiveStorage
99
end
1010

1111
def print_blob(blob, digits: 0)
12-
size = if blob.byte_size < 1024
13-
"#{blob.byte_size}B".rjust(8)
14-
else
15-
"#{blob.byte_size / 1024}K".rjust(8)
16-
end
12+
size = format_size(blob.byte_size)
1713
date = blob.created_at.strftime("%Y-%m-%d %H:%M")
1814
puts "#{size} #{date} #{blob.id.to_s.rjust(digits)} #{blob.filename}"
1915
end
16+
17+
def format_size(bytes)
18+
if bytes >= 1.gigabyte
19+
"#{(bytes / 1.gigabyte.to_f).round(1)}G".rjust(8)
20+
elsif bytes >= 1.megabyte
21+
"#{(bytes / 1.megabyte.to_f).round(1)}M".rjust(8)
22+
elsif bytes >= 1.kilobyte
23+
"#{bytes / 1024}K".rjust(8)
24+
else
25+
"#{bytes}B".rjust(8)
26+
end
27+
end
2028
end
2129
end
2230

2331
namespace :asdb do
2432
desc "ActiveStorageDB: list attachments ordered by blob id desc"
25-
task list: [:environment] do |_t, _args|
26-
query = ActiveStorage::Blob.order(id: :desc).limit(100)
33+
task :list, [:count] => [:environment] do |_t, args|
34+
count = (args[:count] || 100).to_i
35+
query = ActiveStorage::Blob.order(id: :desc).limit(count)
2736
digits = query.ids.inject(0) { |ret, id|
2837
size = id.to_s.size
2938
[size, ret].max

spec/dummy/app/controllers/posts_controller.rb

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def create
3232
format.json { render :show, status: :created, location: @post }
3333
else
3434
format.html { render :new }
35-
format.json { render json: { errors: @post.errors }, status: unprocessable }
35+
format.json { render json: { errors: @post.errors }, status: ActiveStorageDB::UNPROCESSABLE_STATUS }
3636
end
3737
end
3838
end
@@ -46,7 +46,7 @@ def update
4646
format.json { render :show, status: :ok, location: @post }
4747
else
4848
format.html { render :edit }
49-
format.json { render json: { errors: @post.errors }, status: unprocessable }
49+
format.json { render json: { errors: @post.errors }, status: ActiveStorageDB::UNPROCESSABLE_STATUS }
5050
end
5151
end
5252
end
@@ -70,8 +70,4 @@ def load_post
7070
def post_params
7171
params.fetch(:post) { {} }.permit!
7272
end
73-
74-
def unprocessable
75-
Rails::VERSION::MAJOR > 7 || (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1) ? :unprocessable_content : :unprocessable_entity
76-
end
7773
end

spec/dummy/db/schema.rb

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,34 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[7.1].define(version: 20_220_202_010_101) do
13+
ActiveRecord::Schema[7.1].define(version: 2026_03_21_000000) do
1414
create_table "active_storage_attachments", force: :cascade do |t|
15-
t.string "name", null: false
16-
t.string "record_type", null: false
17-
t.bigint "record_id", null: false
1815
t.bigint "blob_id", null: false
1916
t.datetime "created_at", null: false
17+
t.string "name", null: false
18+
t.bigint "record_id", null: false
19+
t.string "record_type", null: false
2020
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
2121
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
2222
end
2323

2424
create_table "active_storage_blobs", force: :cascade do |t|
25-
t.string "key", null: false
26-
t.string "filename", null: false
27-
t.string "content_type"
28-
t.text "metadata"
29-
t.string "service_name", null: false
3025
t.bigint "byte_size", null: false
3126
t.string "checksum", null: false
27+
t.string "content_type"
3228
t.datetime "created_at", null: false
29+
t.string "filename", null: false
30+
t.string "key", null: false
31+
t.text "metadata"
32+
t.string "service_name", null: false
3333
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
3434
end
3535

3636
create_table "active_storage_db_files", force: :cascade do |t|
37-
t.string "ref", null: false
38-
t.binary "data", null: false
3937
t.datetime "created_at", precision: nil, null: false
38+
t.binary "data", null: false
39+
t.string "ref", null: false
40+
t.datetime "updated_at"
4041
t.index ["ref"], name: "index_active_storage_db_files_on_ref", unique: true
4142
end
4243

@@ -47,10 +48,10 @@
4748
end
4849

4950
create_table "posts", force: :cascade do |t|
50-
t.string "title"
5151
t.text "content"
52-
t.boolean "published"
5352
t.datetime "created_at", null: false
53+
t.boolean "published"
54+
t.string "title"
5455
t.datetime "updated_at", null: false
5556
end
5657

0 commit comments

Comments
 (0)