[LRUG] Headache with AR & fields_for

Tom Stuart tom at experthuman.com
Tue Jul 27 11:25:01 PDT 2010


On 27 Jul 2010, at 18:09, Tim Ruffles wrote:
> ruby-1.8.7-p174 > the_recipe = Recipe.with_todos_for(User.find(45)).find(1)
> ruby-1.8.7-p174 > the_recipe.steps
> 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.

I don't completely understand what you're trying to do here, but this is exactly what I'd expect to happen.

ActiveRecord instances don't have any memory of how you found them. I think of Recipe.with_todos_for(User.find(45)).find(1) as returning an object in exactly the same state as the object you get from just Recipe.find(1) -- the named scope doesn't contribute anything to the final object you get back, it just affects whether that object is found or not (i.e. the find will raise ActiveRecord::RecordNotFound if recipe 1 doesn't have any todos for user 45). So yes, naturally, Recipe.find(1).steps will find all steps for that recipe, and Recipe.find(1).steps.first.todos will find all todos for the first step; it doesn't matter how you found that Recipe instance.

I don't know what your use cases are, but in general you may need a "with_todos_for" scope on Step so that you can say recipe.steps.with_todos_for(User.find(45)) ("give me all of this recipe's steps which have todos for user 1"), and/or a "for" scope on Todo so that you can say step.todos.for(User.find(45)) ("give me all this step's todos for user 1").

Since fields_for will optionally take the actual instance or collection you want it to work with (e.g. steps_form.fields_for :todos, step.todos.for(current_user) do ... end) it's not a problem to be explicit about this in the view.

I could have just got the wrong end of the stick, of course. If the above is all nonsense, can you explain what you were hoping Recipe.with_todos_for(User.find(45)).find(1) would do?

Cheers,
-Tom


More information about the Chat mailing list