ActsAsNestedBy
‘acts_as_nested_by’ is/will be a simple counterpart for ActiveRecord::NestedAttributes ‘accepts_attribute_for’.
Installation
-
as gem
$ sudo gem install acts_as_nested_by
-
or as plugin in your rails app
$ ./script/plugin/install git://github.com/tehael/acts_as_nested_by.git # rails 2.3.x $ rails plugin install git://github.com/tehael/acts_as_nested_by.git # rails 3.0.x
Use case example
Since the rails-way of handling referential integrity is to code the logic into you model without using database level foreign key constraints, you might produce code like this.
class Foo < ActiveRecord::Base
has_many :bars
validates_associated :bars
accepts_nested_attributes_for :bars
end
class Bar < ActiveRecord::Base
belongs_to :foo
validates_presence_of :foo
end
Using ‘validates_presence_of :foo’ instead of ‘validates_presence_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 one step produces a dead look, since the ‘:foo_id’ for the Bars is not available until the Foo is saved, and the ‘validates_presence_of :foo’ therefore produces an error in the Bars invalidating them, 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?’ condition with the ‘:validates_presence_of :foo’ might help, but the validation is also skipped, if a ‘Bar’ is not created in a nested way.
To handle this ‘acts_as_nested_by’ comes in handy.
class Bar < ActiveRecord::Base
belongs_to :foo
acts_as_nested_by :foo
validates_presence_of :foo, :unless => :nested_by_foo?
end
For now just pass a parameter (with a hidden form parameter) ‘:nested_by_foo => true’ when creating ‘Bars’ nested in a ‘Foo’. If the ‘Foo’ itsef is ‘valid?’ it can be saved, the nested ‘Bars’ will be auto saved and consistency is assured. ;)
Nota bene
-
The association must be established before ‘calling acts_as_nested_by :foo’, so it must be called after ‘belongs_to :foo’. An ArgumentError will be raised if the association is not yet established.
-
By now the association must be defined by ‘belongs_to’ macro, otherwise an ArgumentError will be raised.
-
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
-
Setting of ‘:nested_by_other’ via mass assignement or by calling ‘nested_by_other = true’ could be exploited to create inconsistent entries.
-
Therefore the mass assignment setter method provided by ‘ActiveRecord#accepts_nested_attributes_for’ should set the ‘:nested_by_other’ flag internaly and ‘ActiveRecord::Base#nested_by_other’ 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
Copyright © 2010 Thomas Limp. See LICENSE for details.