LoginSignup
6
5

More than 5 years have passed since last update.

ActiveRecordのコピー時にPaperclipのAttachmentも正しくコピーする

Last updated at Posted at 2014-12-07

paperclip付きのActiveRecorddupした時にattachmentは同じファイルが別パスにコピーされるようにしようとして、はまりました。

何が起きたか

paperclipのattachmentをコピーする場合、以下のような方法が取れることがネット上でよく書かれている。

imageがpaperclip attachmentだとして、fooimagebarにコピーすることを考えます。

bar.image = foo.image

これ自体は正しいです。
でも、これをインスタンスのコピーdupに適用しようとすると、うまくいかないことがあります。

def dup
  copy = super
  copy.image = self.image
  copy
end

paperclipは内部でアクセッサを動的に定義しており、dupcloneメソッドを使うと、この動的に作られたアクセッサもコピーされてしまいます。
そのため、上のコードで言うと、copy.image === self.imageが成り立つことになります。

解決策

汚いやり方ですが、dup内でアクセッサをクリアします。
paperclipの内部ロジックがpaperclip 4から変わっているので両方に対応させたものが以下です。

  def dup
    copy = super
    if self.respond_to?(:each_attachment)
      copy.instance_variable_set("@_paperclip_attachments", {})
      self.each_attachment do |name, attachment|
        copy.__send__("#{name}=", self.__send__(name)) if self__send__(name).exists?
      end
    # Hack for paperclip 4
    elsif self.class.respond_to?(:attachment_definitions)
      self.class.attachment_definitions.keys.each do |name|
        copy.instance_variable_set("@attachment_#{name}", nil)
        copy.__send__("#{name}=", self.image) if self.__send__(name).exists?
      end
    end
    copy
  end

これで、正しくattachmentをコピーすることができました。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5