Jakob Egger
Jakob Egger

Reputation: 12041

How can I disable lazy loading of active record queries?

I want to query some objects from the database using a WHERE clause similar to the following:

@monuments =  Monument.where("... lots of SQL ...").limit(6)

Later on, in my view I use methods like @monuments.first, then I loop through @monuments, then I display @monuments.count.

When I look at the Rails console, I see that Rails queries the database multiple times, first with a limit of 1 (for @monuments.first), then with a limit of 6 (for looping through all of them), and finally it issues a count() query.

How can I tell ActiveRecord to only execute the query once? Just executing the query once with a limit of 6 should be enough to get all the data I need. Since the query is slow (80ms), repeating it costs a lot of time.

Upvotes: 1

Views: 2811

Answers (2)

coreyward
coreyward

Reputation: 80090

In your situation you'll want to trigger the query before you your call to first because while first is a method on Array, it's also a “finder method” on ActiveRecord objects that'll fetch the first record.

You can prompt this with any method that requires data to work with. I prefer using to_a since it's clear that we'll be dealing with an array after:

@moments = Moment.where(foo: true).to_a
# SQL Query Executed
@moments.first #=> (Array#first) <Moment @foo=true>
@moments.count #=> (Array#count) 42

In this case, you can also use first(6) in place of limit(6), which will also trigger the query. It may be less obvious to another developer on your team that this is intentional, however.

Upvotes: 2

Md. Farhan Memon
Md. Farhan Memon

Reputation: 6121

AFAIK, @monuments.first should not hit the db, I confirmed it on my console, maybe you have multiple instance with same variable or you are doing something else(which you haven't shared here), share the exact code and query and we might debug.

Since, ActiveRecord Collections acts as array, you can use array analogies to avoid querying the db.

Regarding first you can do,

@monuments[0]

Regarding the count, yes, it is a different query which hits the db, to avoid it you can use length as..

@monuments.length

Upvotes: 1

Related Questions