Reputation:
In my app a User can create a Business. When they trigger the index
action in my BusinessesController
I want to check if a Business is related to the current_user.id
:
new
action. I was trying to use this:
if Business.where(:user_id => current_user.id) == nil
# no business found
end
But it always returns true even when the business doesn't exist...
How can I test if a record exists in my database?
Upvotes: 103
Views: 171773
Reputation: 500
Something new to try (:
Assign a variable or return
return unless @business = Business.where(user_id: current_user.id).first
Method would exit at this point if there are no businesses found with current user's ID, or assigns instance variable @business
to the first business object.
Upvotes: 0
Reputation: 54882
Why your code does not work?
The where
method returns an ActiveRecord::Relation object (acts like an array which contains the results of the where
), it can be empty but it will never be nil
.
Business.where(id: -1)
#=> returns an empty ActiveRecord::Relation ( similar to an array )
Business.where(id: -1).nil? # ( similar to == nil? )
#=> returns false
Business.where(id: -1).empty? # test if the array is empty ( similar to .blank? )
#=> returns true
Option 1: Using .exists?
if Business.exists?(user_id: current_user.id)
# same as Business.where(user_id: current_user.id).exists?
# ...
else
# ...
end
Option 2: Using .present?
(or .blank?
, the opposite of .present?
)
if Business.where(:user_id => current_user.id).present?
# less efficiant than using .exists? (see generated SQL for .exists? vs .present?)
else
# ...
end
Option 3: Variable assignment in the if statement
if business = Business.where(:user_id => current_user.id).first
business.do_some_stuff
else
# do something else
end
This option can be considered a code smell by some linters (Rubocop for example).
Option 3b: Variable assignment
business = Business.where(user_id: current_user.id).first
if business
# ...
else
# ...
end
You can also use .find_by_user_id(current_user.id)
instead of .where(...).first
Best option:
Business
object(s): Option 1Business
object(s): Option 3Upvotes: 258
Reputation: 35
I would do it this way if you needed an instance variable of the object to work with:
if @business = Business.where(:user_id => current_user.id).first
#Do stuff
else
#Do stuff
end
Upvotes: 0
Reputation: 3893
business = Business.where(:user_id => current_user.id).first
if business.nil?
# no business found
else
# business.ceo = "me"
end
Upvotes: 1
Reputation: 51
with 'exists?':
Business.exists? user_id: current_user.id #=> 1 or nil
with 'any?':
Business.where(:user_id => current_user.id).any? #=> true or false
If you use something with .where, be sure to avoid trouble with scopes and better use .unscoped
Business.unscoped.where(:user_id => current_user.id).any?
Upvotes: 5
Reputation: 1432
In this case I like to use the exists?
method provided by ActiveRecord:
Business.exists? user_id: current_user.id
Upvotes: 30
Reputation: 5410
When you call Business.where(:user_id => current_user.id)
you will get an array. This Array may have no objects or one or many objects in it, but it won't be null. Thus the check == nil will never be true.
You can try the following:
if Business.where(:user_id => current_user.id).count == 0
So you check the number of elements in the array and compare them to zero.
or you can try:
if Business.find_by_user_id(current_user.id).nil?
this will return one or nil.
Upvotes: 1
Reputation: 2614
ActiveRecord#where will return an ActiveRecord::Relation object (which will never be nil). Try using .empty? on the relation to test if it will return any records.
Upvotes: 1