Checking If Activerecord Find Returns a Result

Checking if ActiveRecord find returns a result

find :all returns an empty array ([]) if no rows are returned, so you can just use it this way:

post = Post.find(:all, :conditions => { :url => params['url'] }, :limit => 1)

unless post.empty?
# do something...
end

By the way, if you do find :all you're going to get an array, not a single row. If you're trying to get just one Post, it would be cleaner to use the find_by helper or find :first or just first instead:

post = Post.find_by_url params['url']

# or

post = Post.first :conditions => { :url => params['url'] }

# then...

if post
# do something...
end

ruby-on-rails check if query result is empty (Model.find)

Use this to check for nil as well as empty cases:

@search.blank?

For the opposite case (NOT nil and NOT empty), use .present?:

@search.present? #equivalent of !@search.blank?

The reason your query returned nil instead of empty is :

Customer.find_by_name($login_name)

always returns one result of object Customer or nil if there is no such result,

while something like:

Customer.where(:name=>$login_name)

will return you ActiveRecord::Relation (which can have 0-n results) always. and empty? method will work on it

Check if record exists from controller in Rails

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


How to test if at least one record exists?

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:

  • If you don't use the Business object(s): Option 1
  • If you need to use the Business object(s): Option 3

Rails - Check if query returns no results

Given the following example models:

# rails g model country name
class Country < ApplicationRecord
has_many :states
has_many :cities, through: :states
end

# rails g model country name country:belongs_to
class State < ApplicationRecord
belongs_to :country
has_many :cities
end

# rails g model city name state:belongs_to
class City < ApplicationRecord
belongs_to :state
has_one :country, through: :state
end

We can get records with matches in joined tables by applying an INNER JOIN:

countries_with_states = Country.joins(:states)
countries_with_cities = Country.joins(states: :cities)
# can be shortened since we have an indirect association
countries_with_cities = Country.joins(:cities)

This will just returns rows with at least one match in the joined table.

We can also get records without matches in the joined table by using a LEFT OUTER JOIN with a condition on the joined table:

countries_with_no_states = Country.left_joins(:states)
.where(states: { id: nil })
countries_with_no_cities = Country.left_joins(:cities)
.where(cities: { id: nil })

Using #map on an association should not be done as its extremely ineffective and can lead to serious performance issues. You instead need to create meaningful associations between your models and use joins to filter the rows in the database.

ActiveSupport's #blank? and #empty? methods should really only be used when dealing with user input like strings and arrays of strings which is where its heuristics are actually useful.

For collections of records you have .exists? which will always create a query and .any? and .none? which will use the size if the relation has been loaded.

Active Record `find` returns nil when a valid record exists

So I found the answer. The problem was with the link in my test: expect(Article).to receive(:find).with(article.id.to_s). Without stating what I want Article.find(params[:id) to return, it returns nil. Hence no error message was received and `find_by(id: params[:id]) worked.

Active Record find_by returns null

I believe you should permit the params, I downloaded your repo and I was able to get the desired query by permitting the params, like this:

class Api::V1::UsersController < ApplicationController

def index
@users = User.find_by(user_params)
respond_to do |format|
format.json { render json: @users.to_json, status: :ok }
end
end

private

def user_params
params.permit(:first_name, :last_name, :email, :city, :state)
end
end

Now if you try this query http://localhost:3000/api/v1/users?first_name=Tyrone&last_name=Slothrop&city=Chicago you should see on the logs that the only the params that you passed are being used for the search:

  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."first_name" = ? AND "users"."last_name" = ? AND "users"."email" = ? AND "users"."city" = ? LIMIT ?  [["first_name", "Tyrone"], ["last_name", "Slothrop"], ["email", "jean@email.com"], ["city", "Chicago"], ["LIMIT", 1]]

↳ app/controllers/api/v1/users_controller.rb:11

Rails is just permitting the params defined on the user_params, so if they're not present, it will just be ignored

Edit: TO return the list of matches you should use where:

  def index
@users = User.where(user_params)
respond_to do |format|
format.json { render json: @users.to_json, status: :ok }
end
end

To allow multiple parameters, for example to allow for multiple first_name fields you can do:

  def user_params
params.permit(:last_name, :email, :city, :state, first_name: [])
end

Remember to put your array items in the end of the permit to avoid syntax errors, and after that you can query the first name like this: http://localhost:3000/api/v1/users?first_name[]=John&first_name[]=Jean,

That url can get pretty tedious to build, so I would suggest that if you are building an api you can always send the params in the body of the request, like this:

{
"first_name": ["John", "Jean"]
}

And that will have the exact behavior of passing the params in the url.

If you strictly want to send the id like id=1,2,3 that you can do something like:

class Api::V1::UsersController < ApplicationController

def index
ids = params[:id].split(",")
@users = User.where(user_params.merge!(id: ids))
respond_to do |format|
format.json { render json: @users.to_json, status: :ok }
end
end

private

def user_params
params.permit(:last_name, :email, :city, :state, :first_name)
end
end

The user_params.merge! will do the trick since it will overwrite or add the id key to your user_params hash.

`detect` and `find` return `nil` whereas `find_all` and `select` return a result

There are two different issues:

1) Why the version with byebug doesn't work

This is the important piece from the docs of find: Returns the first for which block is not false.

Now let's have a look at your cases:

# just writing "true" here, with no if statement will deliver a result

If you just write true at the end of the block then that true is returned and therefore find finds this entry.

if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
ok = true
end
ok

This case is similar: If the if condition is true you assign true to the ok variable. Because you call ok again in the last line of the block the block returns true and find finds this element.

if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
byebug
end

But this example in your code is different. Here you open bundle if the if condition is true. This makes the bundler call the last method call in the find block. Calling bundler doesn't return true therefore the whole block doesn't return true and find doesn't pick these entry.

The solution is to return true in the last line of the find block. Because you have already the condition in your code, you could use that directly without assigning true to a variable first.
– for example like this:

cspg_instance = @game_instances.find do |instance|
instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result

event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period
end

2) Why does find_all and select work, but find does not?

In the comments, you clarified that @game_instances is actually not an Array, but an ActiveRecord::Relation. ActiveRecord::Relation#find works totally different than the method on an Array. Simplified find on such a relation expects an id of a record and returns that record within the scope given by the relation. Calling to_a on the relation loads all records into memory an allows you to use Array#find.

From a performance point of view it would make sense to translate the condition into a SQL condition and only load the one record that matches from the database instead of loading all records and find the correct one in your application.

Rails Find a Record Within ActiveRecord::Relation Object without querying database again

Once the relation has been loaded, you can use regular array methods. find is actually a very interesting method here - if block is specified, it will be delegated to the relation target:

@blogs.find {|b| b.id == 1}

Rails checking if a record exists in database

If you want to check for the existence of an object why not use exists?

if Truck.exists?(10)
# your truck exists in the database
else
# the truck doesn't exist
end

The exists? method has the advantage that is not selecting the record from the database (meaning is faster than selecting the record).
The query looks like:

SELECT 1 FROM trucks where trucks.id = 10

You can find more examples in the Rails documentation for #exists?.



Related Topics



Leave a reply



Submit