acts_as_nested_by

“acts_as_nested_by” is/will be a simple counterpart for rails’ “accepts_attribute_for”.

Use case example

Since the rails-way of handling referential integrity is to code the logic into you your model, without using database dependent foreign key constraints, you might come across situations like this.

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

class Bar < ActiveRecord
  belongs_to :foo
  validates_presence_of :foo
end

Using validates_presence_of :foo instead of :foo_id ensures that not only a :foo_id was given but a Foo object existst in the :foos table.

But on creation of a Foo with nested Bars in on step produces a kind of dead look, since the :foo_id for the Bars is not available until the Foo ist saved, and the validates_presence_of :bars produces an error in the Bars, no :foo_id, no Foo in the :foos table. And because the Foo :validates_associated :bars it cannot be saved. Using an :unless => :new_record? conditions with the validations might help, but it can but those valdation would also be skipped, if the Bars were not to be created in a nested form.

To handle this acts_as_nested_by comes in handy.

class Bar < ActiveRecord
  belongs_to :foo
  acts_as_nested_by :foo
  validates_presence_of :foo, :unless => :nested_by_foo?
end

Now just pass a parameter (with a hidden form parameter, or in the controller) :nested_by_foo => true when creating Bars nested in a Foo. If the Foo ist valid? it can be saved and the nested Bars will be auto saved and consistency is assured. ;)

Nota bene

When using :attr_accessible, :attr_proteced and a hidden form parameter you should add :nested_by_foo to the mass-assignable attributes.

Next steps/known issues

Since the setting of :nested_by_foo via mass assignement could be exploited to create inconsitent entries, the build/create methods provide by the association macros should set the :nested_by_foo internaly and the generated ActiveRecord::Base#nested_by_foo should be defined protected.

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)

  • Send me a pull request. Bonus points for topic branches.

Copyright © 2010 Thomas Limp. See LICENSE for details.