Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building an ActiveRecord relation without having it execute the query

Tags:

I am trying to build a query as follows:

rel = article.where(version: 'some_version')
             .joins(:categories)
             .merge(Category.where(:uuid => 'some_cat_uuid'))

articles = rel.where(published: true).limit(10)
# etc.

The problem is the first query seems to execute no matter what I do. Am I doing something wrong?

like image 983
rainkinz Avatar asked Jul 02 '13 23:07

rainkinz


People also ask

What is an ActiveRecord relation object?

The Relation Class. Having queries return an ActiveRecord::Relation object allows us to chain queries together and this Relation class is at the heart of the new query syntax. Let's take a look at this class by searching through the ActiveRecord source code for a file called relation.

What are ActiveRecord methods?

Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format, and many more.

What does ActiveRecord base mean?

ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending.

What is scope in Ruby on Rails?

Scopes are custom queries that you define inside your Rails models with the scope method. Every scope takes two arguments: A name, which you use to call this scope in your code. A lambda, which implements the query. Example: scope :active_users, -> { where(active: true) }


1 Answers

When you run commands in the console, it automatically adds something similar to .inspect at the end to display the results of the command. For instance (this is in my app that I'm working on right now):

irb(main):061:0> Job.where(id: 251000)
  Job Load (3.8ms)  SELECT "jobs".* FROM "jobs" WHERE "jobs"."deleted_at" IS NULL AND "jobs"."id" = 251000
=> [#<Job id: 251000, {...}>]

So, your first line of code is just fine and would not normally execute the query, but since you were running it in the console it executes immediately so that it can display the results for you.

One way to get around this is to add ; nil to the end of the command, that way the console won't attempt to display the results (it'll just display nil as the result of that line. IE:

irb(main):062:0> Job.where(id: 251000); nil
=> nil

Doing it this way you should be able to do what you were expecting (delay execution of the query until you actually need the results):

rel = article.where(version: 'some_version')
             .joins(:categories)
             .merge(Category.where(:uuid => 'some_cat_uuid')); nil

articles = rel.where(published: true).limit(10); nil

Then you can execute the query by using articles.all (in Rails 3) or articles.to_a (in Rails 4)

Of course if you then move this code to a rake task or model or something you can drop those ; nil bits because they look a little cluttered and would be useless at that point.

Another point of contention for the console might be that it'll see that .where() {NEWLINE} and execute the query at that point, I tend to put the dot on the previous line to remove any ambiguity of where my command is ending:

rel = article.where(version: 'some_version').
             joins(:categories).
             merge(Category.where(:uuid => 'some_cat_uuid')); nil
like image 161
nzifnab Avatar answered Oct 14 '22 15:10

nzifnab