mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Attached one and many
This commit is contained in:
parent
aaf8415188
commit
b7cc003aa0
9 changed files with 139 additions and 41 deletions
34
lib/active_vault/attached.rb
Normal file
34
lib/active_vault/attached.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
require "active_vault/blob"
|
||||
require "active_vault/attachment"
|
||||
|
||||
require "action_dispatch/http/upload"
|
||||
require "active_support/core_ext/module/delegation"
|
||||
|
||||
class ActiveVault::Attached
|
||||
attr_reader :name, :record
|
||||
|
||||
def initialize(name, record)
|
||||
@name, @record = name, record
|
||||
end
|
||||
|
||||
private
|
||||
def create_blob_from(attachable)
|
||||
case attachable
|
||||
when ActiveVault::Blob
|
||||
attachable
|
||||
when ActionDispatch::Http::UploadedFile
|
||||
ActiveVault::Blob.create_after_upload! \
|
||||
io: attachable.open,
|
||||
filename: attachable.original_filename,
|
||||
content_type: attachable.content_type
|
||||
when Hash
|
||||
ActiveVault::Blob.create_after_upload!(attachable)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require "active_vault/attached/one"
|
||||
require "active_vault/attached/many"
|
||||
require "active_vault/attached/macros"
|
15
lib/active_vault/attached/macros.rb
Normal file
15
lib/active_vault/attached/macros.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
module ActiveVault::Attached::Macros
|
||||
def has_one_attached(name)
|
||||
define_method(name) do
|
||||
instance_variable_get("@active_vault_attached_#{name}") ||
|
||||
instance_variable_set("@active_vault_attached_#{name}", ActiveVault::Attached::One.new(name, self))
|
||||
end
|
||||
end
|
||||
|
||||
def has_many_attached(name)
|
||||
define_method(name) do
|
||||
instance_variable_get("@active_vault_attached_#{name}") ||
|
||||
instance_variable_set("@active_vault_attached_#{name}", ActiveVault::Attached::Many.new(name, self))
|
||||
end
|
||||
end
|
||||
end
|
22
lib/active_vault/attached/many.rb
Normal file
22
lib/active_vault/attached/many.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
class ActiveVault::Attached::Many < ActiveVault::Attached
|
||||
delegate_missing_to :attachments
|
||||
|
||||
def attachments
|
||||
@attachments ||= ActiveVault::Attachment.where(record_gid: record.to_gid.to_s, name: name)
|
||||
end
|
||||
|
||||
def attach(*attachables)
|
||||
@attachments = attachments + Array(attachables).collect do |attachable|
|
||||
ActiveVault::Attachment.create!(record_gid: record.to_gid.to_s, name: name, blob: create_blob_from(attachable))
|
||||
end
|
||||
end
|
||||
|
||||
def attached?
|
||||
attachments.any?
|
||||
end
|
||||
|
||||
def purge
|
||||
attachments.each(&:purge)
|
||||
@attachments = nil
|
||||
end
|
||||
end
|
24
lib/active_vault/attached/one.rb
Normal file
24
lib/active_vault/attached/one.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
class ActiveVault::Attached::One < ActiveVault::Attached
|
||||
delegate_missing_to :attachment
|
||||
|
||||
def attachment
|
||||
@attachment ||= ActiveVault::Attachment.find_by(record_gid: record.to_gid.to_s, name: name)
|
||||
end
|
||||
|
||||
def attach(attachable)
|
||||
if @attachment
|
||||
# FIXME: Have options to declare dependent: :purge to clean up
|
||||
end
|
||||
|
||||
@attachment = ActiveVault::Attachment.create!(record_gid: record.to_gid.to_s, name: name, blob: create_blob_from(attachable))
|
||||
end
|
||||
|
||||
def attached?
|
||||
attachment.present?
|
||||
end
|
||||
|
||||
def purge
|
||||
attachment.purge
|
||||
@attachment = nil
|
||||
end
|
||||
end
|
|
@ -22,6 +22,5 @@ class ActiveVault::Attachment < ActiveRecord::Base
|
|||
def purge
|
||||
blob.purge
|
||||
destroy
|
||||
record.public_send "#{name}=", nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
require "active_vault/attachment"
|
||||
require "action_dispatch/http/upload"
|
||||
|
||||
module ActiveVault::Attachments
|
||||
def has_file(name)
|
||||
define_method(name) do
|
||||
(@active_vault_attachments ||= {})[name] ||=
|
||||
ActiveVault::Attachment.find_by(record_gid: to_gid.to_s, name: name)&.tap { |a| a.record = self }
|
||||
end
|
||||
|
||||
define_method(:"#{name}=") do |attachable|
|
||||
case attachable
|
||||
when ActiveVault::Blob
|
||||
blob = attachable
|
||||
when ActionDispatch::Http::UploadedFile
|
||||
blob = ActiveVault::Blob.create_after_upload! \
|
||||
io: attachable.open,
|
||||
filename: attachable.original_filename,
|
||||
content_type: attachable.content_type
|
||||
when Hash
|
||||
blob = ActiveVault::Blob.create_after_upload!(attachable)
|
||||
when NilClass
|
||||
blob = nil
|
||||
end
|
||||
|
||||
(@active_vault_attachments ||= {})[name] = blob ?
|
||||
ActiveVault::Attachment.create!(record_gid: to_gid.to_s, name: name, blob: blob)&.tap { |a| a.record = self } : nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,11 +16,11 @@ module ActiveVault
|
|||
end
|
||||
end
|
||||
|
||||
initializer "action_file.attachments" do
|
||||
require "active_vault/attachments"
|
||||
initializer "action_file.attached" do
|
||||
require "active_vault/attached"
|
||||
|
||||
ActiveSupport.on_load(:active_record) do
|
||||
extend ActiveVault::Attachments
|
||||
extend ActiveVault::Attached::Macros
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,23 +5,57 @@ require "active_vault/blob"
|
|||
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
has_file :avatar
|
||||
has_one_attached :avatar
|
||||
has_many_attached :highlights
|
||||
end
|
||||
|
||||
class ActiveVault::AttachmentsTest < ActiveSupport::TestCase
|
||||
setup { @user = User.create!(name: "DHH") }
|
||||
|
||||
test "create attachment from existing blob" do
|
||||
@user.avatar = create_blob filename: "funky.jpg"
|
||||
teardown { ActiveVault::Blob.all.each(&:purge) }
|
||||
|
||||
test "attach existing blob" do
|
||||
@user.avatar.attach create_blob(filename: "funky.jpg")
|
||||
assert_equal "funky.jpg", @user.avatar.filename.to_s
|
||||
end
|
||||
|
||||
test "attach new blob" do
|
||||
@user.avatar.attach io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg"
|
||||
assert_equal "town.jpg", @user.avatar.filename.to_s
|
||||
end
|
||||
|
||||
test "purge attached blob" do
|
||||
@user.avatar = create_blob filename: "funky.jpg"
|
||||
@user.avatar.attach create_blob(filename: "funky.jpg")
|
||||
avatar_key = @user.avatar.key
|
||||
|
||||
@user.avatar.purge
|
||||
assert_nil @user.avatar
|
||||
assert_not @user.avatar.attached?
|
||||
assert_not ActiveVault::Blob.site.exist?(avatar_key)
|
||||
end
|
||||
|
||||
test "attach existing blobs" do
|
||||
@user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg")
|
||||
|
||||
assert_equal "funky.jpg", @user.highlights.first.filename.to_s
|
||||
assert_equal "wonky.jpg", @user.highlights.second.filename.to_s
|
||||
end
|
||||
|
||||
test "attach new blobs" do
|
||||
@user.highlights.attach(
|
||||
{ io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" },
|
||||
{ io: StringIO.new("IT"), filename: "country.jpg", content_type: "image/jpg" })
|
||||
|
||||
assert_equal "town.jpg", @user.highlights.first.filename.to_s
|
||||
assert_equal "country.jpg", @user.highlights.second.filename.to_s
|
||||
end
|
||||
|
||||
test "purge attached blobs" do
|
||||
@user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg")
|
||||
highlight_keys = @user.highlights.collect(&:key)
|
||||
|
||||
@user.highlights.purge
|
||||
assert_not @user.highlights.attached?
|
||||
assert_not ActiveVault::Blob.site.exist?(highlight_keys.first)
|
||||
assert_not ActiveVault::Blob.site.exist?(highlight_keys.second)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,8 +20,8 @@ class ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
|
||||
require "active_vault/attachments"
|
||||
ActiveRecord::Base.send :extend, ActiveVault::Attachments
|
||||
require "active_vault/attached"
|
||||
ActiveRecord::Base.send :extend, ActiveVault::Attached::Macros
|
||||
|
||||
require "global_id"
|
||||
GlobalID.app = "ActiveVaultExampleApp"
|
||||
|
|
Loading…
Reference in a new issue