Module: Refile::ActiveRecord::Attachment

Includes:
Refile::Attachment
Defined in:
lib/refile/attachment/active_record.rb

Instance Method Summary collapse

Instance Method Details

#accepts_attachments_for(association_name, attachment: :file, append: false) ⇒ void

This method returns an undefined value.

Macro which generates accessors for assigning multiple attachments at once. This is primarily useful together with multiple file uploads.

The name of the generated accessors will be the name of the association and the name of the attachment in the associated model. So if a ‘Post` accepts attachments for `images`, and the attachment in the `Image` model is named `file`, then the accessors will be named `images_files`.

Examples:

in model

class Post
  has_many :images, dependent: :destroy
  accepts_attachments_for :images
end

in associated model

class Image
  attachment :image
end

in form

<%= form_for @post do |form| %>
  <%= form.attachment_field :images_files, multiple: true %>
<% end %>

Parameters:

  • association_name (Symbol)

    Name of the association

  • attachment (Symbol) (defaults to: :file)

    Name of the attachment in the associated model

  • append (Symbol) (defaults to: false)

    If true, new files are appended instead of replacing the entire list of associated models.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/refile/attachment/active_record.rb', line 78

def accepts_attachments_for(association_name, attachment: :file, append: false)
  association = reflect_on_association(association_name)
  attachment_pluralized = attachment.to_s.pluralize
  name = "#{association_name}_#{attachment_pluralized}"

  mod = Module.new do
    define_method :"#{name}_attachment_definition" do
      association.klass.send("#{attachment}_attachment_definition")
    end

    define_method(:method_missing) do |method|
      if method == attachment_pluralized.to_sym
        raise NoMethodError, "wrong association name #{method}, use like this #{name}"
      else
        super(method)
      end
    end

    define_method :"#{name}_data" do
      if send(association_name).all? { |record| record.send("#{attachment}_attacher").valid? }
        send(association_name).map(&:"#{attachment}_data").select(&:present?)
      end
    end

    define_method :"#{name}" do
      send(association_name).map(&attachment)
    end

    define_method :"#{name}=" do |files|
      cache, files = files.partition { |file| file.is_a?(String) }

      cache = Refile.parse_json(cache.first)

      if not append and (files.present? or cache.present?)
        send("#{association_name}=", [])
      end

      if files.empty? and cache.present?
        cache.select(&:present?).each do |file|
          send(association_name).build(attachment => file.to_json)
        end
      else
        files.select(&:present?).each do |file|
          send(association_name).build(attachment => file)
        end
      end
    end
  end

  include mod
end

#attachment(name, raise_errors: false, destroy: true, **options) ⇒ void

This method returns an undefined value.

Attachment method which hooks into ActiveRecord models

Parameters:

  • destroy (true, false) (defaults to: true)

    Whether to remove the stored file if its model is destroyed

See Also:



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/refile/attachment/active_record.rb', line 11

def attachment(name, raise_errors: false, destroy: true, **options)
  super(name, raise_errors: raise_errors, **options)

  attacher = "#{name}_attacher"

  validate do
    if send(attacher).present?
      send(attacher).valid?
      errors = send(attacher).errors
      errors.each do |error|
        self.errors.add(name, *error)
      end
    end
  end

  define_method "#{name}=" do |value|
    send("#{name}_id_will_change!") if respond_to?("#{name}_id_will_change!")
    super(value)
  end

  define_method "remove_#{name}=" do |value|
    send("#{name}_id_will_change!")
    super(value)
  end

  define_method "remote_#{name}_url=" do |value|
    send("#{name}_id_will_change!")
    super(value)
  end

  before_save do
    send(attacher).store!
  end

  after_destroy do
    send(attacher).delete! if destroy
  end
end