ActiveRecord query error in rails - ruby-on-rails

So I have an ActiveRecord query in a controller:
t="example_name"
i = Item.where(:name => t)
This doesn't cause an error, but it doesn't seem to be returning the right thing. In the rails console, it returns a normal Item and I can access all the attributes, but looking at some print statements I put in, I can see that
i.class = Item::ActiveRecord_Relation
Whereas when I make the call as
i = Item.find(4)
for debugging purposes,
i.class = Item
I can't figure out why this is happening, especially since the where() query works in the rails console

Anytime you use a #where query in Rails, it returns as an ActiveRecord::Relation. This is beneficial to you, because Rails is avoiding the performance overhead and just saying, "I found these results according to the query you gave me."
Here's a link to the Rails docs.

Related

Problems working with the output of the YouTube_It gem in Rails

I've been messing around with the Youtube_It gem for the past couple of days as I'm trying to integrate it into a Rails 4 app I'm currently working on.
When I run a search query with it, it outputs an array with a ton of results. As long as I'm in the Rails console, there's no problem with manipulating it. A brief example :
require 'youtube_it'
client = YouTubeIt::Client.new(:dev_key => "dev_key")
data = client.videos_by(:query => "penguin")
data.videos.each { |v| puts v.unique_id }
This outputs a nice, tidy list of all the unique id's that were returned from the query.
When I try to do something similar within a view (I know it shouldn't really be in the view, it's simply there for testing at this point) it just outputs a huge jumbled list of what appears to be XML. This only seems to happen when I try to iterate using .each.
When I do something like :
<% data = client.videos_by(:query => "penguin") %>
<%= data.videos[1].unique_id %>
This returns exactly what I was expecting, one unique_id from the index that I chose. Great! But how do I get ALL the unique id's?
That's where I'm stuck and would really appreciate some help! :)
OK, two reasons (working from the gist you gave me on IRC, located here):
1) You are not actually using the same code as in the console. Your console uses puts unique_id which will print the value of the unique ID, but you are just using unique_id which will get the ID... and then do nothing with it. What you want is probably something like data.videos.map(&:unique_id) (or data.videos.map { |v| v.unique_id } in long form) which will return you an array of the IDs.
2) You are using <%=, which means 'evaluate this ruby line and output the return value onto the page'. The return value of an each statement is the object you called each on - ie. data.videos, so that is what is getting printed out.

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

How is this method memory intense?

I found the following method to be a HEAVY memory user on Ruby 1.8.7 and return absolutely no results (when there should be lots). The method also works like a charm on Ruby 1.9.2, returning all the wanted results while consuming no memory at all (or so!). I guess that's because a local variable has the same name as the containing method, but anyone have a clear answer for that?
def contact_of
contact_of = Circle.joins(:ties).where('ties.contact_id' => self.guid).map { |circle| circle.owner } || []
return contact_of.uniq!
end
By the way, I'm running Rails 3.1.1.
Thanks!
UPDATE : There's a part of the question that is erroneous. The fact that no contacts are returned when there should be is my misunderstading of 'uniq!' instead of 'uniq'. The first one does return 'nil' when no duplicates are found.
Still trying to figure out the memory problem...
Yeah, contact_of.uniq! would make a recursive call to the same function. I'm surprised it works in Ruby 1.9, actually.
Also, your DB query is terrible, because it retrieves a lot of unnecessary records and then does further select logic on the Ruby side. You probably want to start the find from Owner, not Circle.

Why Active Record relation is not returned in console?

I have finally started upgrading my Rails apps from 2.3.8 to 3.1.0. I was watching RailsCasts (http://railscasts.com/episodes/202-active-record-queries-in-rails-3) about Active Record queries.
When I open up the console (rails c) and do query similar to this:
articles = Article.order("name")
Instead of returning Active Record relations, I see the query executed. What am I doing wrong here?
Rails version: 3.1.0
RVM on 1.9.2
Thank you for your help!
EDIT: I have added a screenshot from the example.
The ActiveRecord Relation class is configured to perform the query when a query method like .all, .last, .first, ... is invoked. The list of method also includes .inspect, the same method called by the console to display the representation of the return value.
For this reason it seems to you that the object is never a relation, because you always see the result of the query.
But if you inspect the object class, you'll notice it's a relation
Article.order("name").class
# => ActiveRecord::Relation
You're doing everything right. You see query executed because console invokes inspect method on output. Try articles = Article.order("name").class

Resources