Reputation: 10208
I have a strange problem.
I have two models Users and roles with a many to many relationships between them. I want to filter the roles with name 'Administrator' within the role collection of a user.
In the model this code
puts self.roles.to_s
Prints to screen: [Role id: 1, name: "Administrator", created_at: "2012-01-22 21:55:45", updated_at: "2012-01-22 21:55:45"]
But this code
puts self.roles.find_by_name('Administrator').to_s
doesn't print anything. And this one:
puts self.roles.find_by_name('Administrator').nil?
prints true!
Why isn't my find_by_name method not working? I tryied it in the console and it works well.
My code snippet is the following:
puts self.roles.to_s
puts self.roles.find_by_name('Administrator').to_s
puts self.roles.find_by_name('Administrator').nil?
And the output is the following:
[Role id: 1, name: "Administrator", created_at: "2012-01-22 21:55:45", updated_at: "2012-01-22 21:55:45"]
<none>
true
What am I doing wrong?? It has to be something stupid. This code is located in a validate method, so it is executed before the user is saved.
Upvotes: 1
Views: 4854
Reputation: 124409
You mentioned that you are doing this in a validation before the model is saved. This is why it's failing. Since the User
is not yet saved, it doesn't have an id
in your database, so there's no way for it to search your associations.
The reason the first line works (self.roles.to_s
) is that Rails memorizes any roles you add to your user, but does not save them to the database until you save the user. Once you save the user, your second/third lines would work fine:
user = User.new
user.roles << Role.first
user.roles
# => [#<Role id: 1, name: "Administrator" ...>]
user.roles.find_by_name("Administrator")
# => nil
user.save # This inserts both the new user AND the associations
user.roles.find_by_name("Administrator")
# => #<Role id: 1, name: "Administrator" ...>
If you have to work with this in your validations, you might try using Enumerable's find
method to search the roles
array instead:
user = User.new
user.roles << Role.first
user.roles
# => [#<Role id: 1, name: "Administrator" ...>]
user.roles.find { |role| role.name == "Administrator" }
# => #<Role id: 1, name: "Administrator" ...>
user.roles.find { |role| role.name == "Foo" }
# => nil
Upvotes: 3