Today I was writing Shoulda tests for my models. The tests were very trivial.
should_have_many :properties
should_accept_neste...
As my fingers twirled hastily across the sensually-clicking macbook keyboard with an obsessive goal to produce erroneous line #3 I thought to myself “oh wait!”
There is no such macro! We have this new awesome convenience method ‘accepts_nested_attributes_for :something’ (let’s call it “anaf” for short) and no shoulda macros to test it.
Without a second thought I continued.
Let’s write that baby.
First thing, let’s create the shoulda macro folder in your test dir if you don’t have it yet. This ‘shoulda_macros’ dir is magical as it will be detected and autoloaded by shoulda. (Thanks to this blog post for the pointer.)
~% mate test/shoulda_macros/accepts_nested_attributes_for_macros.rb
And now the code almighty.
def should_accept_nested_attributes_for(*attr_names)
klass = self.name.gsub(/Test$/, '').constantize
context "#{klass}" do
attr_names.each do |association_name|
should "accept nested attrs for #{association_name}" do
assert klass.instance_methods.include?("#{association_name}_attributes="),
"#{klass} does not accept nested attributes for #{association_name}"
end
end
end
end
end
class ActiveSupport::TestCase
extend AcceptsNestedAttributesForMacros
end
Turns out it’s as simple as squishing a Caribbean crazy ant. You just go through each supplied symbol and assert that the
method exists in your model. Yay, and now my
will actually work!
Now I tried to do it better. I swear. I tried to make it validate options like
, but I can’t figure out how to do it without nasty perversions. The Rails’ anaf macro essentially class_evals a new method in which it calls another method with a hard-coded meta-parameter coming outside of closure. I’m simply not ninja enough yet to introspect to such extent.
There is however one way to do it. Hire a friendly worker from a poor country to read and assert your code for you every time you run tests. Put something like a red flashing light in their room and monkeypatch a callback into your rake task.
Hi, Since you have been able to get accepts_nested_attributes_for to work, I am hoping that you can tell me what I need to do. I have installed the latest activerecord gem 2.2.2, but I don’t seem to have this method. The api info says that it is in activerecord/lib/active_record/nested_attributes.rb, but I have no such file. What am I missing? Thanks. Greg
In order to get that method you’ll either have to get yourself up to tag 2.3.0 or get Edge. 2.2.2 didn’t have this feature yet. For more info check out this blog post. In fact, I suggest you subscribe to that blog for clean and concise updates on what’s going on with rails.
Neat. How would pass these nested attributes as params for controller tests, say if you are using Factory Girl for stepping away from fixtures…
This is strictly a unit test, verifying that model has accepts_nested_attributes_for declared. If you want to test its behavior in the context of your app – you’d have to write custom tests in your functionals.
Ahh, just what I was looking for. Thanks for saving me the hassle of having to write this!
You should see if you can get this upstream in shoulda with a pull request… just add it to this file:
http://github.com/thoughtbot/shoulda/blob/7d6aa5b6ecceef0bef3399bc328275a3700e06ac/lib/shoulda/active_record/macros.rb
It is now part of shmacros. I’d rather stick to that plugin for now. : )