When I assign a database find to an instance variable in Rails, why do future requests to that variable also hit the database? Can this be avoided?
For example, I have 3 models: User, Resource, Opinion, with has_many :through on Opinion
@opinions = current_user.opinions # pulls in all of the user's opinions, which include respective resource ids
1. Calling for resource_id directly does not hit the database:
@opinions.each do |opinion|
opinion.resource_id # does not hit the database (as expected)
end
2. Performing a query does hit the database (even though variable has been assigned):
@opinions.find_by_resource_id(1) # DOES hit the database
Why does #2 hit the database? Is there a way to perform the same find without hitting the database?
The information is already contained in the @opinions variable, so a db call does not seem necessary.
If you don’t need anything else in the
@opinionsarray, I would scope your original query to only include opinions with thatresource_idIf you already have
@opinionsand just want to create a new array of objects that match for a specific key/value:Check out this other answer for another explanation or if you want to split the answer into multiple arrays.
Thoughts
Comment on your last piece of code
Methods like you called
find_by_*are dynamic finders that usemethod_missingto hit the database and look inside of the column specified by the *.Remaining comments from previous answer
If this object will ever need to access data on the Resource model, don’t forget about the
#includes()method, which will keep you from having to run additional queries down the road.See http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations