When I have array of ids, like
ids = [2,3,5]
and I perform
Comment.find(ids)
everything works fine. But when there is id that doesn't exist, I get an exception. This occurs generaly when I get list of IDs that match some filter and than I do something like
current_user.comments.find(ids)
This time I may have a valid comment ID, which however does not belong to given User, so it is not found and I get an exception.
I've tried find(:all, ids)
, but it returns all of the records.
The only way I can do it now is
current_user.comments.select { |c| ids.include?(c.id) }
But that seems to me like super inefficient solution.
Is there better way to select ID in Array without getting exception on non-existing record?
If it is just avoiding the exception you are worried about, the "find_all_by.." family of functions works without throwing exceptions.
Comment.find_all_by_id([2, 3, 5])
will work even if some of the ids don't exist. This works in the
user.comments.find_all_by_id(potentially_nonexistent_ids)
case as well.
Update: Rails 4
Comment.where(id: [2, 3, 5])
Update: This answer is more relevant for Rails 4.x
Do this:
current_user.comments.where(:id=>[123,"456","Michael Jackson"])
The stronger side of this approach is that it returns a Relation
object, to which you can join more .where
clauses, .limit
clauses, etc., which is very helpful. It also allows non-existent IDs without throwing exceptions.
The newer Ruby syntax would be:
current_user.comments.where(id: [123, "456", "Michael Jackson"])
where
syntax when comparing to an array. I thought I might have to code the SQL with an IN
statement, but this looks cleaner and is an easy replacement for the deprecated scoped_by_id
.
If you need more control (perhaps you need to state the table name) you can also do the following:
Model.joins(:another_model_table_name)
.where('another_model_table_name.id IN (?)', your_id_array)
your_id_array
when you get the objects back?
ORDER BY
won't work in my situation because the order is not based on an attribute. However, there is a way to do it via SQL (so it's fast) and someone has even created a gem for it. Check out this Q&A: stackoverflow.com/questions/801824/…
Now .find and .find_by_id methods are deprecated in rails 4. So instead we can use below:
Comment.where(id: [2, 3, 5])
It will work even if some of the ids don't exist. This works in the
user.comments.where(id: avoided_ids_array)
Also for excluding ID's
Comment.where.not(id: [2, 3, 5])
To avoid exceptions killing your app you should catch those exceptions and treat them the way you wish, defining the behavior for you app on those situations where the id is not found.
begin
current_user.comments.find(ids)
rescue
#do something in case of exception found
end
Here's more info on exceptions in ruby.
You can also use it in named_scope if You want to put there others conditions
for example include some other model:
named_scope 'get_by_ids', lambda { |ids| { :include => [:comments], :conditions => ["comments.id IN (?)", ids] } }
Success story sharing
Array
instead of anActiveRecord::Relation
, which limits what you can do with it afterwards.Comment.where(id: [2, 3, 5])
does return anActiveRecord::Relation
.