Module: Ripple::NestedAttributes::ClassMethods

Defined in:
lib/ripple/nested_attributes.rb

Overview

Nested Attributes

This is similar to the accepts_nested_attributes functionality as found in AR. This allows the use update attributes and create new child records through the parent. It also allows the use of the fields_for form view helper, using a presenter pattern.

To enable in the model, call the class method, using the same relationship as defined in the one or many.

class Shipment
  include Ripple::Document
  one :box
  many :addresses
  accepts_nested_attributes_for :box, :addresses
end

One

Given this model:

class Shipment
  include Ripple::Document
  one :box
  accepts_nested_attributes_for :box
end

This allows creating a box child during creation:

shipment = Shipment.create(:box_attributes => { :shape => 'square' })
shipment.box.shape # => 'square'

This also allows updating box attributes:

shipment.update_attributes(:box_attributes => { :key => 'xxx', :shape => 'triangle' })
shipment.box.shape # => 'triangle'

Many

Given this model

class Manifest
  include Ripple::Document
  many :shipments
  accepts_nested_attributes_for :shipments
end

This allows creating several shipments during manifest creation:

manifest = Manifest.create(:shipments_attributes => [ { :reference => "foo1" }, { :reference => "foo2" } ])
manifest.shipments.size # => 2
manifest.shipments.first.reference # => foo1
manifest.shipments.second.reference # => foo2

And updating shipment attributes:

manifest.update_attributes(:shipment_attributes => [ { :key => 'xxx', :reference => 'updated foo1' },
                                                     { :key => 'yyy', :reference => 'updated foo2' } ])
manifest.shipments.first.reference # => updated foo1
manifest.shipments.second.reference # => updated foo2

NOTE: On many embedded, then entire collection of embedded documents is replaced, as there is no key to specifically update.

Given

class Manifest
  include Ripple::Documnet
  many :signatures
  accepts_nested_attributes_for :signatures
end

class Signature
  include Ripple::EmbeddedDocument
  property :esignature, String
end

The assigning of attributes replaces existing:

manifest = Manifest.create(:signature_attributes => [ { :esig => 'a00001' }, { :esig => 'b00001' } ]
manifest.signatures # => [<Signature esig="a00001">, <Signature esig="b00001">]

manifest.signature_attributes = [ { :esig => 'c00001' } ]
manifest.signatures # => [<Signature esig="c00001">]

Instance Method Summary collapse

Instance Method Details

#accepts_nested_attributes_for(*attr_names) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/ripple/nested_attributes.rb', line 117

def accepts_nested_attributes_for(*attr_names)
  options = { :allow_destroy => false }
  options.update(attr_names.extract_options!)
  
  attr_names.each do |association_name|
    if association = self.associations[association_name]
      nested_attributes_options[association_name.to_sym] = options
   
      class_eval %{
        def #{association_name}_attributes=(attributes)
          assign_nested_attributes_for_#{association.type}_association(:#{association_name}, attributes)
        end

        before_save :autosave_nested_attributes_for_#{association_name}
        before_save :destroy_marked_for_destruction

        private

        def autosave_nested_attributes_for_#{association_name}
          save_nested_attributes_for_#{association.type}_association(:#{association_name}) if self.autosave[:#{association_name}]
        end
      }, __FILE__, __LINE__
    else
      raise ArgumentError, "Association #{association_name} not found!"
    end
  end        
end