Module: Ripple::NestedAttributes::ClassMethods

Defined in:
ripple/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

- (Object) accepts_nested_attributes_for(*attr_names)



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 'ripple/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