[LRUG] Headache with AR & fields_for
Tim Ruffles
tim at cothink.co.uk
Tue Jul 27 10:09:14 PDT 2010
Hi, I'm having a problem with AR - I've only been playing with Rails
for 3 months or so, perhaps I'm missing something on this :)
I'm really happy with AR and fields_for, it cut out a load of cruft.
But today I realised my form wasn't working as expected. When I
perform query #1 although the filtering for each step's todos is
already specified, a new query is performed when I call step.todos if
no Todo was returned initially. with_todos_for is a named scope that
uses SQL on the joins to add stuff to the ON clause.
I had a long look at the Rails API and can't see anything that could
help (tried freezing, disconnecting. I guess I need to mark the
'todos' association as already searched for, so no further query is
made). Essentially as no Todos are returned for the Steps, they
requery without any user filter, pulling in all of a Step's todos
unfiltered.
(Query #1) ruby-1.8.7-p174 > the_recipe =
Recipe.with_todos_for(User.find(45)).find(1)
Recipe Load (9.0ms) SELECT "recipes".* FROM "recipes" LEFT OUTER
JOIN steps ON recipes.id = steps.recipe_id LEFT OUTER JOIN todos ON
todos.step_id = steps.id AND todos.user_id = 45 WHERE ("recipes"."id"
= 1)
ruby-1.8.7-p174 > the_recipe.steps
Step Load (4.5ms) SELECT * FROM "steps" WHERE ("steps".recipe_id
= 1)
ruby-1.8.7-p174 > the_recipe.steps.first.todos
Todo Load (3.4ms) SELECT * FROM "todos" WHERE ("todos".step_id =
30)
=> [#<Todo id: 30, step_id: 30, user_id: 43, completed_date:
"2010-07-27 16:43:30", reminder_date: nil, created_at: "2010-07-27
16:43:22", updated_at: "2010-07-27 16:43:51">]
As you can see, we now have a Todo with a user_id 43, not the 45 that
the initial query requested - it's worse as in the real version it
pulls in everybody's todos.
This second load is triggered by the following line in my view:
- form_for recipe, :url => {:action => :update} do |recipe_form|
....
- recipe_form.fields_for :steps do |steps_form|
- step = steps_form.object
- step.todos.create :user => current_user if step.todos.empty?
# this triggers query #3, and pulls in all todos, causing hundreds of
iterations for the following fields_for:
%li
- steps_form.fields_for :todos do |f|
....
Anyone got any ideas? It'd be great to keep the controller as simple
as fields_for normally allows!
Thanks,
Tim Ruffles
More information about the Chat
mailing list