Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Rails, what is the inverse of update_attributes?

In Rails, what is the inverse of update_attributes! ?

In other words, what maps a record to an attributes hash that would recreate that record and all of it children records?

The answer is not ActiveRecord.attributes as that will not recurse into child object.

To clarify if you have the following:

class Foo < ActiveRecord::Base
  has_many :bars
  accepts_nested_attributes_for :bars
end

Then you can pass an hash like

{"name" => "a foo", "bars_attributes" => [{"name" => "a bar} ...]}

to update_attributes. But it's not clear how to easily generate such a hash programatically for this purpose.

EDIT:
As I have mentioned in a comment, I can do something like:
foo.as_json(:include => :bars)

but I wanted a solution that uses the accepts_nested_attributes_for :bars declaration to avoid having to explicitly include associations.

like image 611
Mark Bolusmjak Avatar asked Jan 28 '14 15:01

Mark Bolusmjak


1 Answers

Not sure how that would be the "inverse", but while Rails might not "have the answer" per-see, there is nothing stopping you from traversing through an object and creating this VERY efficiently.

Something to get you started:

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for

You'll notice in the accepts_nested_attributes_for method, rails sets a hash for all models nested, in nested_attributes_options. So we can use that to get these nested associations, to populate this new hash.

def to_nested_hash
  nested_hash = self.attributes.delete_if {|key, value| [:id, :created_at, :deleted_at].include? key.to_sym } # And any other attributes you don't want

  associations = self.nested_attributes_options.keys
  associations.each do |association|
    key = "#{association}_attributes"
    nested_hash[key] = []
    self.send(association).find_each do |child|
      nested_hash[key] << child.attributes.delete_if {|key, value| [:id, :created_at, :deleted_at].include? key.to_sym }
    end
  end

  return nested_hash
end

OR just thought of this:

Using your example above:

foo.as_json(:include => foo.nested_attributes_options.keys)

One thing to note, this won't give you the bars_attributes where my first suggestions will. (neither will serializable_hash)

like image 157
omarvelous Avatar answered Nov 16 '22 22:11

omarvelous