Rails 3- find_by not working

4.7k views Asked by At

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.

1

There are 1 answers

0
Dylan Markow On BEST ANSWER

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