Check that the keys related to the association are not modified inside the block. Does not use an ensure block, so callers should be careful.
# File lib/sequel/plugins/nested_attributes.rb, line 143 143: def nested_attributes_check_key_modifications(reflection, obj) 144: keys = reflection.associated_object_keys.map{|x| obj.send(x)} 145: yield 146: unless keys == reflection.associated_object_keys.map{|x| obj.send(x)} 147: raise(Error, "Modifying association dependent key(s) when updating associated objects is not allowed") 148: end 149: end
Create a new associated object with the given attributes, validate it when the parent is validated, and save it when the object is saved. Returns the object created.
# File lib/sequel/plugins/nested_attributes.rb, line 154 154: def nested_attributes_create(reflection, attributes) 155: obj = reflection.associated_class.new 156: nested_attributes_set_attributes(reflection, obj, attributes) 157: after_validation_hook{validate_associated_object(reflection, obj)} 158: if reflection.returns_array? 159: send(reflection[:name]) << obj 160: after_save_hook{send(reflection.add_method, obj)} 161: else 162: associations[reflection[:name]] = obj 163: 164: # Because we are modifying the associations cache manually before the 165: # setter is called, we still want to run the setter code even though 166: # the cached value will be the same as the given value. 167: @set_associated_object_if_same = true 168: 169: # Don't need to validate the object twice if :validate association option is not false 170: # and don't want to validate it at all if it is false. 171: send(reflection[:type] == :many_to_one ? :before_save_hook : :after_save_hook){send(reflection.setter_method, obj.save(:validate=>false))} 172: end 173: obj 174: end
Take an array or hash of attribute hashes and set each one individually. If a hash is provided it, sort it by key and then use the values. If there is a limit on the nested attributes for this association, make sure the length of the attributes_list is not greater than the limit.
# File lib/sequel/plugins/nested_attributes.rb, line 180 180: def nested_attributes_list_setter(reflection, attributes_list) 181: attributes_list = attributes_list.sort_by{|x| x.to_s}.map{|k,v| v} if attributes_list.is_a?(Hash) 182: if (limit = reflection[:nested_attributes][:limit]) && attributes_list.length > limit 183: raise(Error, "number of nested attributes (#{attributes_list.length}) exceeds the limit (#{limit})") 184: end 185: attributes_list.each{|a| nested_attributes_setter(reflection, a)} 186: end
Remove the given associated object from the current object. If the :destroy option is given, destroy the object after disassociating it (unless destroying the object would automatically disassociate it). Returns the object removed.
# File lib/sequel/plugins/nested_attributes.rb, line 192 192: def nested_attributes_remove(reflection, obj, opts={}) 193: if !opts[:destroy] || reflection.remove_before_destroy? 194: before_save_hook do 195: if reflection.returns_array? 196: send(reflection.remove_method, obj) 197: else 198: send(reflection.setter_method, nil) 199: end 200: end 201: end 202: after_save_hook{obj.destroy} if opts[:destroy] 203: obj 204: end
Set the fields in the obj based on the association, only allowing specific :fields if configured.
# File lib/sequel/plugins/nested_attributes.rb, line 208 208: def nested_attributes_set_attributes(reflection, obj, attributes) 209: if fields = reflection[:nested_attributes][:fields] 210: obj.set_only(attributes, fields) 211: else 212: obj.set(attributes) 213: end 214: end
Modify the associated object based on the contents of the attributes hash:
If a :transform block was given to nested_attributes, use it to modify the attribute hash.
If a block was given to nested_attributes, call it with the attributes and return immediately if the block returns true.
If a primary key exists in the attributes hash and it matches an associated object:
** If _delete is a key in the hash and the :destroy option is used, destroy the matching associated object. ** If _remove is a key in the hash and the :remove option is used, disassociated the matching associated object. ** Otherwise, update the matching associated object with the contents of the hash.
If a primary key exists in the attributes hash but it does not match an associated object, either raise an error, create a new object or ignore the hash, depending on the :unmatched_pk option.
If no primary key exists in the attributes hash, create a new object.
# File lib/sequel/plugins/nested_attributes.rb, line 226 226: def nested_attributes_setter(reflection, attributes) 227: if a = reflection[:nested_attributes][:transform] 228: attributes = a.call(self, attributes) 229: end 230: return if (b = reflection[:nested_attributes][:reject_if]) && b.call(attributes) 231: modified! 232: klass = reflection.associated_class 233: sym_keys = Array(klass.primary_key) 234: str_keys = sym_keys.map{|k| k.to_s} 235: if (pk = attributes.values_at(*sym_keys)).all? || (pk = attributes.values_at(*str_keys)).all? 236: pk = pk.map{|k| k.to_s} 237: obj = Array(send(reflection[:name])).find{|x| Array(x.pk).map{|k| k.to_s} == pk} 238: end 239: if obj 240: attributes = attributes.dup.delete_if{|k,v| str_keys.include? k.to_s} 241: if reflection[:nested_attributes][:destroy] && klass.db.send(:typecast_value_boolean, attributes.delete(:_delete) || attributes.delete('_delete')) 242: nested_attributes_remove(reflection, obj, :destroy=>true) 243: elsif reflection[:nested_attributes][:remove] && klass.db.send(:typecast_value_boolean, attributes.delete(:_remove) || attributes.delete('_remove')) 244: nested_attributes_remove(reflection, obj) 245: else 246: nested_attributes_update(reflection, obj, attributes) 247: end 248: elsif pk.all? && reflection[:nested_attributes][:unmatched_pk] != :create 249: if reflection[:nested_attributes][:unmatched_pk] == :raise 250: raise(Error, "no matching associated object with given primary key (association: #{reflection[:name]}, pk: #{pk})") 251: end 252: else 253: nested_attributes_create(reflection, attributes) 254: end 255: end
Update the given object with the attributes, validating it when the parent object is validated and saving it when the parent is saved. Returns the object updated.
# File lib/sequel/plugins/nested_attributes.rb, line 260 260: def nested_attributes_update(reflection, obj, attributes) 261: nested_attributes_update_attributes(reflection, obj, attributes) 262: after_validation_hook{validate_associated_object(reflection, obj)} 263: # Don't need to validate the object twice if :validate association option is not false 264: # and don't want to validate it at all if it is false. 265: after_save_hook{obj.save_changes(:validate=>false)} 266: obj 267: end
Update the attributes for the given object related to the current object through the association.
# File lib/sequel/plugins/nested_attributes.rb, line 270 270: def nested_attributes_update_attributes(reflection, obj, attributes) 271: nested_attributes_check_key_modifications(reflection, obj) do 272: nested_attributes_set_attributes(reflection, obj, attributes) 273: end 274: end
Validate the given associated object, adding any validation error messages from the given object to the parent object.
# File lib/sequel/plugins/nested_attributes.rb, line 278 278: def validate_associated_object(reflection, obj) 279: return if reflection[:validate] == false 280: association = reflection[:name] 281: obj.errors.full_messages.each{|m| errors.add(association, m)} unless obj.valid? 282: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.