Rails: Getting column value from query - ruby-on-rails

Seems like it should be able to look at a simple tutorial or find an aswer with a quick google, but I can't...
codes = PartnerCode.find_by_sql "SELECT * from partner_codes where product = 'SPANMEX' and isused = 'false' limit 1"
I want the column named code, I want just the value. Tried everything what that seems logical. Driving me nuts because everything I find shows an example without referencing the actual values returned
So what is the object returned? Array, hash, ActiveRecord? Thanks in advance.

For Rails 4+ (and a bit earlier I think), use pluck:
Partner.where(conditions).pluck :code
> ["code1", "code2", "code3"]
map is inefficient as it will select all columns first and also won't be able to optimise the query.

You need this one
Partner.where( conditions ).map(&:code)
is shorthand for
Partner.where( conditions ).map{|p| p.code}
PS
if you are often run into such case you will like this gem valium by ernie
it gives you pretty way to get values without instantiating activerecord object like
Partner.where( conditions ).value_of :code
UPDATED:
if you need access some attribute and after that update record
save instance first in some variable:
instance=Partner.where( conditions ).first
then you may access attributes like instance.code and update some attribute
instance.update_attribute || instance.update_attributes
check documentation at api.rubyonrails.org for details

Related

Rails 4 update_all and set value from another field

I need to do some bulk updates in some models and set value of a field as value of another field.
Right now I can do that with raw sql like this:
ActiveRecord::Base.connection.execute("UPDATE `deleted_contents` SET `deleted_contents`.`original_id` = `deleted_contents`.`id` WHERE `deleted_contents`.`original_id` is NULL")
This is working fine, however I need to do this using ActiveRecord query interface due to many reasons.
I tried:
DeletedContent.where(original_id: nil).update_all(original_id: value_of_id_column)
For value_of_id_column I tried :id, self.id, id, etc, nothing works. What should I set for value_of_id_column to get the original query generated by rails? Is this possible, or using the raw sql is the only solution?
Also I do not want to iterate over each record and update. This is not a valid solution for me:
DeletedContent.where(original_id: nil).each do |deleted_content|
update_each_record
end
I'm pretty sure you cannot obtain that query by passing a hash to update_all.
The closest to what you want to obtain would be:
DeletedContent.where(original_id: nil).update_all("original_id = id")

How to access dynamic attribute 'geo_near_distance' with Mongoid

I am using Mongoid 3.1.6 with Rails 4. I need to find all the objects 'near' a certain co-ordinate. For each result from the search, I will need to display the distance from the search co-orodinate. According to Mongoid Documentation
...each instantiated document from a $geoNear query will get a special
dynamic attribute geo_near_distance that will be available as long as
the document is in memory.
But I am not able to access the Object.geo_near_distance
My query inside controller...
#objects = Object.geo_near([-118.4451, 34.0633]).max_distance(10)
Edit#1
Some additional details
If the use the following query in MongoDB
db.runCommand( { geoNear: "objects",
near: [ -73.95269,40.77578],
spherical: true
})
I see an array of 100 elements. Each element has 2 attributes. The first one, 'dis' has values like '0.000123' (Note: this is not in Km or Mile) and the second attribute is the result Object itself.
Now I have changed the query to Mongoid to...
#objects = Object.geo_near([-118.4451, 34.0633]).spherical.max_distance(10)
still no result.
Thanks in advance for your help.
After more than 2 years, the issue ticket is still open on mongodb jira tracker.
The quick fix is not use the hash notation instead of the dot notation to access the attribute:
Instead of
Object.geo_near_distance
Use
Object['geo_near_distance']
Tested on mongoid 6
Are you accessing the field while you are iterating the documents? You can see by the specs that this field is in fact there when the document is in memory and is being part of the iteration of the criteria result.
https://github.com/mongoid/mongoid/blob/master/spec/mongoid/contextual/geo_near_spec.rb#L167

How do I order database records in rails by most recent?

I want to order all the items in a model Item so it displays the most recent ones first. According to the Rails guide, the following code should work:
Item.order("created_at DESC")
However, when I type that (or varieties) in the terminal, the most recent item always shows up last, and that's how they show up on my page. How do I efficiently retrieve them with he most recent first? (I'm going to display only some of them at a time on each page.)
Note that my default scope for items is oldest first.
Update:
This is the SQL I get:
SELECT "comments".* FROM "comments" ORDER BY comments.created_at ASC, created_at DESC
So I guess I shouldn't use default scopes...
The query you posted is correct
Item.order("created_at DESC")
The only reason why it would not work is if there is anything else conflicting with it. In general, the conflict is represented by a default_scope.
If you have a default scope that overrides your order, you should first unscope the query
Item.unscoped { Item.order("created_at DESC") }
If you are using default scopes, I strongly encourage you to avoid them. They are very hard to debug and unscope.
There are very few cases where default scopes make sense. You can simply pass the (default) scope at select time in the controller or create a custom method for it.
I realise this is a really old question, but none of the answers contain the solution without writing raw SQL, which is available since Rails 3+:
Item.order(created_at: :desc)
or using the reverse_order method:
Item.order(:created_at).reverse_order
See more at http://guides.rubyonrails.org/active_record_querying.html#ordering
and
http://guides.rubyonrails.org/active_record_querying.html#reverse-order.
I modified CDub's answer with reverse so it now works:
Item.order(:created_at).reverse
I'm still not sure why the Rails guide's way doesn't work. Also the above method doesn't work well with pagination.
Item.unscoped.order('created_at DESC') should work.Using reverse might decrease the performance when the number of records increases
Correct one and tested
#purchase_orders = current_company.purchase_orders.order(:date)
#purchase_orders = #purchase_orders.reverse_order
you can add You can also define the default order in Item model
default_scope order('created_at DESC')

AcitveRecord where method that matches just one record

Program.where(name: "xxyyzz123") will return a collection, even if there's just one record that matches which forces me to do ugly things like:
puts Program.where(name: "xxyyzz123").first.age
or
puts Program.where(name: "xxyyzz123")[0].age
When I know for sure only one record will match, is there a shorter way to grab a property from that one record?
ActiveRecord's dynamic attribute-based finders (find_by_x) allow you to select the first record that matches in your database. For example:
Program.find_by_name('xxyyzz123')
will return the first record with name = 'xxyyzz123'
Note that these finders are 'mildly deprecated' in Rails 4. Using
Program.find_by(name: 'xxyyzz123")
achieves the same thing and may make it easier when needing to update to the next version of Rails if they ever remove the former's functionality.
See ActiveRecord::Base in the API for more.
Yes, you will have to access that with Program.where(name: "xxyyzz123").first.age, however, in Rails 3, it is usually recommended to do that type of query with: Program.find_by_name('xxyyzz123').age.
Rails 4 deprecates the above syntax and recommends you to use the following syntax for that:
Program.find_by(name: 'xxyyzz123')
If you have multiple conditions, then simply : Program.find_by(name: 'xxyyzz123', lang: 'ruby')
Behind the scene, it does the same tomfoolery - where clause and returns first object.

Saving updates to objects in rails

I'm trying to update one of my objects in my rails app and the changes just don't stick. There are no errors, and stepping through with the debugger just reveals that it thinks everything is updating.
Anyway, here is the code in question...
qm = QuestionMembership.find(:first, :conditions => ["question_id = ? AND form_id = ?", q_id, form_id])
qm.position = x
qm.save
For reference sake, QuestionMembership has question_id, form_id, and position fields. All are integers, and have no db constraints.
That is basically my join table between Forms and Questions.
Stepping through the code, qm gets a valid object, the position of the object does get changed to the value of x, and save returns 'true'.
However, after the method exits, the object in the db is unchanged.
What am I missing?
You may not be finding the object that you think you are. Some experimenting in irb might be enlightening.
Also, as a general rule when changing only one attribute, it's better to write
qm.update_attribute(:position, x)
instead of setting and saving. Rails will then update only that column instead of the entire row. And you also get the benefit of the data being scrubbed.
Is there an after_save?
Is the correct SQL being emitted?
In development log, you can actually see the sql that is generated.
For something like this:
qm = QuestionMembership.find(:first, :conditions => ["question_id = ? AND form_id = ?", q_id, form_id])
qm.position = x
qm.save
You should see something to the effect of:
SELECT * FROM question_memberships WHERE question_id=2 AND form_id=6 LIMIT 1
UPDATE question_memberships SET position = x WHERE id = 5
Can you output what sql you are actually seeing so we can compare?
Either update the attribute or call:
qm.reload
after the qm.save
What is the result of qm.save? True or false? And what about qm.errors, does that provide anything that makes sense to you? And what does the development.log say?
I have run into this problem rather frequently. (I was about to say consistently, but I cannot, as that would imply that I would know when it was about to happen.)
While I have no solution to the underlying issue, I have found that it seems to happen to me only when I am trying to update mysql text fields. My workaround has been to set the field to do something like:
qm.position = ""
qm.save
qm.position = x
qm.save
And to answer everyone else... when I run qm.save! I get no errors. I have not tried qm.save?
When I run through my code in the rails console everything works perfectly as evidenced by re-finding the object using the same query brings the expected results.
I have the same issue when using qm.update_attribute(... as well
My workaround has gotten me limping this far, but hopefully someone on this thread will be able to help.
Try changing qm.save to qm.save! and see if you get an exception message.
Edit: What happens when you watch the log on the call to .save!? Does it generate the expected SQL?
Use ./script/console and run this script.. step by step..
see if the position field for the object is update or not when you run line 2
then hit qm.save or qm.save!... to test
see what happens. Also as mentioned by Tim .. check the logs
Check your QuestionMembership class and verify that position does not have something like
attr_readonly :position
Best way to debug this is to do
tail -f log/development.log
And then open another console and do the code executing the save statement. Verify that the actual SQL Update statement is executed.
Check to make sure your database settings are correct. If you're working with multiple databases (or haven't changed the default sqlite3 database to MySQL) you may be working with the wrong database.
Run the commands in ./script/console to see if you see the same behavior.
Verify that a similar object (say a Form or Question) saves.
If the Form or Question saves, find the difference between the QuestionMembership and Form or Question object.
Turns out that it was emitting the wrong SQL. Basically it was looking for the QuestionMembeship object by the id column which doesn't exist.
I was under the impression that that column was unnecessary with has_many_through relationships, although it seems I was misguided.
To fix, I simply added the id column to the table as a primary key. Thanks for all the pointers.

Resources