I’m trying to do stuff with models nested one layer deeper than I’ve
done in the past…and it’s just not working properly. Here’s the
situation:
I have three models involved here: Recipe, IngredientLine, and
Ingredient (it’s a cookbook application).
class Recipe < ActiveRecord::Base
has_many :ingredient_lines
has_many :ingredients, :through => :ingredient_lines
end
class IngredientLine < ActiveRecord::Base
belongs_to :ingredient
belongs_to :recipe
end
class Ingredient < ActiveRecord::Base
has_many :ingredient_lines
has_many :recipes, :through => :ingredient_lines
end
I’m trying to develop a form which edits a Recipe along with its
associated IngredientLines and Ingredients. Right now, I’ve been
working with this sort of thing (it’s a Facebook app, hence the .fbml
extension, and I’m only doing relevant excerpts so as not to take up
too much space here):
ff.fields_for :ingredient do |i|
%td= i.text_field :name, :id => nil
I’ve tried this with fields_for instead of f.fields_for as well.
There’s some JavaScript to produce multiple copies of the partial
for multiple ingredient, but I’m omitting that since it’s not relevant
here.
The HTML/FBML output for this is as expected:
So far so good. But here’s the problem: submissions don’t work quite
properly. When I fill out the form and submit it, I get params
entries like
“recipe”=>{“name”=>“Recipe”, “ingredient_lines”=>[{“quantity”=>“1”,
“unit”=>“cup”, “ingredient”=>{}}], “instructions”=>“Preheat oven to
350°…”}. Note that ingredient_lines[0].ingredient.name is missing,
even if I enter text in the corresponding form field – in other
words, what I should be seeing is something like “recipe”=>
{“name”=>“Recipe”, “ingredient_lines”=>[{“quantity”=>“1”,
“unit”=>“cup”, “ingredient”=>{“name” => “flour”}}],
“instructions”=>“Preheat oven to 350°…”}. What am I doing wrong?
Any suggestions would be helpful. Thanks in advance!
words, what I should be seeing is something like “recipe”=>
{“name”=>“Recipe”, “ingredient_lines”=>[{“quantity”=>“1”,
“unit”=>“cup”, “ingredient”=>{“name” => “flour”}}],
“instructions”=>“Preheat oven to 350°…”}.
I believe this is a limitation of Rails’ parameter parsing.
It can’t handle more that one level below an array parameter.
A solution is to create an ingredient_name accessor in
IngredientLine, and arrange to have this rendered and posted.
I believe this is a limitation of Rails’ parameter parsing.
I was afraid of that. This may be the excuse I need to start hacking
the core.
It can’t handle more that one level below an array parameter.
Are you sure? I’ve seen a few examples on the Web which imply that
this should work.
By “array parameter”, do you specifically mean one with a numeric
subscript, so that object[foo][bar][baz] would work as expected,
although objects[][foo][bar][baz] would not? If so, that would
explain some – not all – of the examples I’ve seen.
A solution is to create an ingredient_name accessor in
IngredientLine, and arrange to have this rendered and posted.
It can’t handle more that one level below an array parameter.
Are you sure? I’ve seen a few examples on the Web which imply that
this should work.
I can confirm that it’s broken in Rails 2.0.2, and fixed
in Rails >= 2.1.0.
By “array parameter”, do you specifically mean one with a numeric
subscript, so that object[foo][bar][baz] would work as expected,
although objects[][foo][bar][baz] would not? If so, that would
explain some – not all – of the examples I’ve seen.
objects[][foo] works, but objects[][foo][bar] did not.
Thanks for the suggestion. I tried the same test, and got interesting
if disheartening results. When I had recipe[ingredient_lines][]
[ingredient][name] as the only form field, I got the same results as
you. But the moment I added recipe[ingredient_lines][][unit],
[ingredient][name] stopped working. This was true both with Rails
2.1.2 and 2.2.2. I think I may be running into a bug in Rails.
objects[][foo] works, but objects[][foo][bar] did not.
And still apparently does not. Any other thoughts?
The test I did was to post from the following view.
On Rails >= 2.1 I got the correct
“recipe”=>{“ingredient_lines”=>[{“ingredient”=>{“name”=>“hhh”}}]}
on 2.0.2 I got what you’re seeing:
“recipe”=>{“ingredient_lines”=>[{“ingredient”=>{}}]}
You may like to run the same test.
If you see the same, perhaps the problem manifests when extra
parameters are added. You can try adding fields until you
are posting your complete form. Please post what you find out.
Thanks for the suggestion. I tried the same test, and got interesting
if disheartening results. When I had recipe[ingredient_lines][]
[ingredient][name] as the only form field, I got the same results as
you. But the moment I added recipe[ingredient_lines][][unit],
[ingredient][name] stopped working. This was true both with Rails
2.1.2 and 2.2.2. I think I may be running into a bug in Rails.
Thanks for running that test.
Below is a patch that seems to fix the problem. I haven’t
yet run the rails test suite on it, nor added a test that would
have broken the original.
Just run the patch command in actionpack-2.2.2/lib/action_controller
Below is a patch that seems to fix the problem. I haven’t
yet run the rails test suite on it, nor added a test that would
have broken the original.
I’ve confirmed that this patch fixes the problem without regression.
Hey, this is quite a Christmas present – thanks very much! I was
about to start poking around in the core to fix this, but you beat me
to it. (The patch you posted here didn’t actually work, but the one
on the Lighthouse ticket did.) And it solves the problem beautifully.