Rails, attachment_fu - cópia profunda de acessórios de armazenamento de banco de dados
-
18-09-2019 - |
Pergunta
Eu tenho um modelo, digamos Anexos, que usos attachment_fu para aceitar o upload de arquivos do usuário. Eu quero "cópia profunda" (ou em Ruby-ese, clone de profundidade) um anexo, criando assim um novo objeto binário na tabela "db_files".
Descobri que não é bem um problema resolvido ainda. Esta postagem de blog: http://www.williambharding.com/blog / rails / rails-rápido-clonecopy-de-attachment_fu-images /
Mostra um método que supostamente trabalha para armazenamento baseado em sistema de arquivos. Para as lojas à base de db, a "cópia profunda" falha. Um novo "anexo" é criado, mas ele usa o db_file_id pré-existente, realizando assim uma cópia superficial.
db_file_backend.rb de Dentro attachment_fu vejo o método Save:
# Saves the data to the DbFile model
def save_to_storage
if save_attachment?
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
true
end
Então, eu estou tentando decifrar isso e eu acredito "build_db_file" é algum rubi taquigrafia metaprogramming mágica para DbFile.new embora eu não posso confirmar isso (grepping os shows de origem nenhuma menção a isso, nem posso encontrá-lo no google) .
Eu não tenho certeza do que ele está fazendo, mas minha teoria é que o DB_File está sendo copiado do obj origem como parte da tentativa de "cópia Deep" (no código ligada), portanto, é simplesmente provocando um save em vez de um criar.
A minha teoria inicial era de que o (Anexo) objeto pai seria definida como "novo" em cima de uma tentativa de cópia profunda, assim eu fiz algo como:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
end
true
end
Isso realmente funciona bem para objetos clonados mas infelizmente todos os testes para envios regulares, não clonados de arquivo falhar. O objeto anexo é criado, mas não dados são gravados DB_File. A teoria é que o objeto pai é salvo pela primeira vez, em seguida, o material DB_File está escrito mais tarde, assim new_record? retorna falso.
Assim, como uma experiência, decidi tentar:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
else
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
#end
end
true
end
Isso funciona parcialmente - o DB_File é preenchida mas depois eu recebo um erro no db_file.save! -. Dizer que DB_File é nulo
Então, eu sou uma espécie de frustrado. Eu posso fazer mais alguma tentativa e erro, mas neste momento eu bati minha limitada compreensão de como funciona este plugin. Eu realmente não esperava ou quer gastar tanto tempo com isso, então eu estou relutante em tentar explorar attachment_fu mais longe, mas eu tenho medo que eu vou ter que ir no buraco do coelho para descobrir isso. Todas as ideias ou pensamentos?
Thanks !!
Solução 2
Ok, então em vez de descobrir como criar um novo DB_File (que é um desperdício no nosso caso particular) destroy_file, eu só remendado-macaco apenas excluir o DB_File se não há mais registros de fixação apontando para ele. Isto pode não ser apropriado se você permitir que alguém "modificar" um DB_File anexo In situ , mas desde que não o fizermos, isso funciona muito bem.
Technoweenie::AttachmentFu::Backends::DbFileBackend.module_eval do
protected
def destroy_file
if db_file && self.class.count( :conditions =>["id <> ? AND db_file_id = ?", self.id, db_file.id] ) == 0
db_file.destroy
end
end
end
Outras dicas
Esta é apenas uma resposta parcial explicando a chamada build_db_file
Como você suspeita, a chamada build_db_file
executa um método gerado através da criação associação belongs_to
. A associação é criado aqui:
def self.included(base) #:nodoc:
Object.const_set(:DbFile, Class.new(ActiveRecord::Base)) unless Object.const_defined?(:DbFile)
base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id'
end
Assim, a declaração (db_file || build_db_file)
leva um objeto DbFile
associado existente ou cria um novo se é nulo, e atribui o temp_data à sua data
campo binário. O temp_data
é, provavelmente, a matriz de bytes com os dados a partir do formulário.
E eu tenho uma pergunta (eu não posso comentar sobre a sua pergunta) - por que não chamar db_file.save!
depois de criá-la com
db_file = DbFile.new :data => temp_data
?