Rails 4 update_all and set value from another field - ruby-on-rails

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")

Related

active record how do I specify a column after a join?

I'm trying to make an sql query using activerecord and I'm having a hard time specifying a specific column from multiple joined tables.
for instance in sql
select go.id, sequence.name, sequence.id from sequence join (goterms,...) on ...
this is not beautiful sql but my point is that I'm able to specify which .id I want returned
in activerecord I'm doing this:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name)
.distinct
I want to be able to get id from :Goterm but :Taxa and :Foreigndb also use id as a column in the database so i'm getting uninformative errors that I assume stem from this issue when I do the following.
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name,:id)
.distinct
What is the correct way to just specify that I want Goterm.id?
edit - Here is the error:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'Goterm.id' in 'field list'
when I run:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass,:genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).dresults = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).distinct
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name, 'sequences.id')
.distinct
It turns out that ilan's answer is correct, however be sure that everything is lower case. I was using 'Goterm.id' to make the selection when it needs to be 'goterm.id'
If anyone else runs into this, I also ran into difficulties grabbing the goterm.id data out of the returned query objects. Each time I called object.id on that return set it would give me something different from what I was expecting. I think the attribute I was expecting was being obscured by something else. To get the data I needed I did the following:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus,:interpro_desc,:description,:dbname,:read_depth, :name).distinct
firstRes = results[0]
firstRes.attributes['id']

Returning a hash instead of array with ActiveRecord::Base.connection

I have to use a query like this :
query = Enc.joins(:rec).group("enc.bottle").
select("enc.bottle as mode, count(rec.id) as numrec, sum(enc.value) as sumvalue")
That I use with :
#enc = ActiveRecord::Base.connection.select_all(query)
To get the data, I've to do #enc.rows.first[0] (it works)
But #enc.rows.first["mode"] doesn't work ! Because each row of #enc.rows contains array.. not a map with the name of each field.
Maybe select_all is a wrong method.
Does it exist another method to get the data with the name of field ?
Thank you
EDIT
If you can associate a model with the query, then there's no need for the generic select_all method. You can use find_by_sql like this:
Enc.find_by_sql(query).first.mode
# => testing
Note that you will no be able to see the aliases when inspecting the results, but they are there. Also, the convention is to use plural names for the tables. You might find it easier to just sticks with the defaults.

proper way to debug sql result in rails

I'm currently using
puts #object.inspect
to debug the results of queries in rails, but the output doesn't seem to include any joins I've defined for the query. How do I get the full array to show?
For example, if I do the following
#object = Object.joins("JOIN associations ON associations.id = object.association_id")
.where(:id => params[:object_id])
.select("objects.*, associations.*")
.first
puts #object.inspect
I get the all the Object fields in my debug array, but none of the association fields. Yet they are there when I try to use them in my view (#object.association_field etc)
PS - the above query looks ugly, I'm only trying to pull one record, but I was getting various errors if I tried to use .find() instead of .where().first. Suggestions welcome on how to make it more railsy
Why not the simplest possible way:
#object = Object.find(params[:object_id])
#association = #object.associations.first
puts "#{#object.inspect}, #{#association.inspect}"
(assuming that has_many :associations is defined in Object)
And the reason you are not getting fields for association is because the only thing that joins does is joining to another table in SQL. It does not fetch joined data. select only select subset of object's attributes, I think the rest is just ignored.

Rails: Getting column value from query

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

How to get table column value?

I write follow code to get one record from the table webeehs:
webeehs_result = Webeeh.find(:all, :conditions=>["webeeh_project_id=#{project_id}"])
Then I want to get one column value from this record, how could I do?
For example, the column name is webeeh_date.
first of all, never EVER write code like that. Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. If you must do conditions, then do it like this:
:conditions => ["webeeh_project_id = ?", project_id]
if you have a Project model, you should rename the webeeh_project_id column from your Webeeh model into project_id and have an association in your Project model like has_many :webeehs
Then, you won't need to call that find anymore, just do a p = Project.find(id) and then p.webeehs will return the webeehs you need.
the result will be an array which you can iterate through. And to get your webeeh.webeeh_date member, just call it like this:
result.each do |webeeh|
date = webeeh.webeeh_date
end
webeehs_result = Webeeh.findwebeeh_dates
is enough to get all columnn values.
For a different method and performance issues check the following: http://www.stopdropandrew.com/2010/01/28/finding-ids-fast-with-active-record.html
webeeh_result will usually be an array of results for the database.
You can iterate throughit using
webeehs_result.each do |webeeh|
# use "webeeh.webeeh_date" to access the column_name or do whatever you want with it.
end

Resources