stop meta_search doing sql to early - ruby-on-rails

in the docs it's said:
MyObject.search()
returns an instance of MetaSearch::Builder (something like ActiveRecord::Relation). But in my case when I do this I get a collection of objects because the sql-query is send to the database.
I would like to have something like this:
search = MyObject.search() # no sql-query should be done here
count = search.count # count sql done
objects = search.all # select sql done - maybee with pagination
does anyone know how to stop Meta_search from doing the the query to early?
-> ok, something mysterious going on in my shell:
search = MyObject.search() # queries the database
search = MyObject.search(); 0 # stores a MetaSearch-Object in search
the console seems to call an extra method after each comand

If you're testing in irb, be aware that returned objects are inspected. In the case of a MetaSearch builder, this means the relation gets inspected. If you have a look at ActiveRecord's inspect method, in relation.rb, you'll see that it calls to_a, which executes the query and returns the results.

Related

ActiveRecord: Check Number of Database Calls

For demo purposes, suppose that I have a class called DemoThing with a method called do_something.
Is there a way that (in code) I can check the number of times that do_something hits the database? Is there a way that I can "spy" on active record to count the number of times that the database was called?
For instance:
class DemoThing
def do_something
retVal = []
5.times do |i|
retVal << MyActiveRecordModel.where(:id => i)
end
retVal
end
end
dt = DemoThing.new
stuff = dt.do_something # want to assert that do_something hit the database 5 times
ActiveRecord should be logging each query in STDOUT.
But for the above code, it's pretty obvious that you're making 5 calls for each iteration of i.
Queries can be made more efficient by not mixing Ruby logic with querying.
In this example, gettings the ids before querying will mean that the query isn't called for each Ruby loop.
ids = 5.times.to_a
retVal = MyActiveRecordModel.where(id: ids) # .to_a if retVal needs to be an Array
Sure is. But first you must understand Rails' Query Cache and logger. By default, Rails will attempt to optimize performance by turning on a simple query cache. It is a hash stored on the current thread (one for every active database connection - Most rails processes will have just one ). Whenever a select statement is made (like find or where etc.), the corresponding result set is stored in a hash with the SQL that was used to query them as the key. You'll notice when you run the above method your log will show Model Load statement and then a CACHE statement. Your database was only queried one time, with the other 4 being loaded via cache. Watch your server logs as you run that query.
I found a gem for queries count https://github.com/comboy/sql_queries_count

Rails Active Record Omitting Where Clause

I have an Active Record query that sits inside of a gem. Database used is postgres.
Client.where(date:#date,client:#business_id)
The gem uses a get request to pull this data. When there are too many values in #business_id, the URI is too long. Gem does not have post requests.
Workaround:
The business problem is when all the #business_id get passed to the app. I could have an "all" button, that triggers all the client values to show. I would need to ignore the client:#business_id part of the query.
How could I construct the query so that when all of the #business_id need to be passed, it ignores the client:#business_id part of the query?
chain the where clause and then conditionally include or exclude the #business_id part:
relation = Client.where(date:#date)
if your_conditional_is_true
relation = relation.where(client:#business_id)
end
the_clients = relation.all
The reason this works is that where actually returns an ActiveRelation, not the results of executing the SQL. The SQL is not built and executed until you do something to work on the results of the relation.

Active record create query in multiple steps

I'm a bit confused by active record, it just seems to fire the query at any time you stop, ie.
#model.where( :store_id => #sid )
Which is fine, but what if I want to build a query like this:
query = #model.where( :store_id => #sid )
if(some_condition)
query.offset(50)
and then execute the query (not actually what I'm doing but a very simple example). Is there a way to put together the query in steps and then tell it to execute?
Actually, ActiveRecord will do exactly what you want. It's called lazy loading. You might be getting confused by the rails console, which calls .inspect behinds the scenes on the result of the line.
Check out this question: Lazy loading in Rails 3.2.6
This already works like you want it too.
where() returns an instance of ActiveRecord::Relation.
The relation won't execute it's database call until it needs to. The reason you might be experiencing otherwise is that you're testing it in the console, which prints the output of each statement (thus loading the relation). You can test whether a relation has been loaded via the loaded() method.
Try this on the console:
m = #model.where(:store_id => #sid); # the semicolon will silence the output
m.loaded? # nil
m # executes db call, will print out the contents of the relation
m.loaded? # true

How to preview a delete_all or destroy_all query in Rails

You know the drill: some invalid data pops up in the production database and you have to get rid of it. You fire up your Rails console on the production server and type in the query:
Foo.where(bar: 'baz').all
You review the returned data and it's what you need to remove. Then you type:
Foo.where(bar: 'baz').destroy_all
And your heart stops for a second. You just want to see the query before it runs.
Is there any way to do that in Rails? I'm looking for a method similar to
Foo.where(bar: 'baz').to_sql
but the one that will return the DELETE query.
Just off the top of my head, you could run the console in sandbox mode and run the delete query to see the sql. The changes would just be rolled back on exit.
The problem is that destroy_all does not run a single SQL query. It iterates through a hash of objects, instantiates them, runs their callbacks, and then calls that object's destroy method. Rails has no built-in way of producing an array of these queries.
Cdesroisiers is right that you can test the query in sandbox mode, but the real problem is that you're second-guessing your decision to run delete_all, even though you've verified whatever data is being targeted.
Consider using an ActiveRecord versioning gem like PaperTrail if you're not willing to trust ActiveRecord to properly delete objects.
the destroy_all method is the same as doing:
Foo.where(bar: 'baz').each { |object| object.destroy }
So the sql becomes
DELETE FROM foo WHERE foo.id = your_objects_id_attribute
From docs:
def destroy_all(conditions = nil)
find(:all, :conditions => conditions).each { |object| object.destroy }
end

Using Rails ActiveRecord to Query Unsaved Objects

Is it possible to query unsaved changes using Rail's ActiveRecord or another similar approach?
An example of a Ruby interactive session is below. What I'd like to see, is the fourth line show a result of '999' instead of '10'. I'm use to using .NET and Entity Framework where something similar to this was possible. Perhaps in Ruby there is a better or different way to do the same thing. I could obviously add up the sum in a loop, but I find the query syntax more elegant. Any help is appreciated.
i = Inventory.where(:product_id => 1)
i.sum(:available) => 10
i.first.available = 999
i.sum(:available) => 10
No, since sum() is actually translated to SQL and run on the db, you must save the record to the db in order for the query to return the result you want.
Alternatively, you can use the Enumerable#sum method in ActiveSupport, which takes a block, like so:
all = Inventory.where(:product_id => 1).to_a
all.first.available = 999
all.sum(&:available)

Resources