I have a rails app with a Customer and a ShippingAddress model. It is implemented with a one-to-many relationship so that a ShippingAddress can have multiple customers.
I am successfully able to query across these two models and several others with an include statement, but as I tried to update the query to find all of the customers that does not have a shipping_address got 0 results, even though I am able to se from my DB-admin tool that I have multiple customers where the value of the shipping_address_id is nil.
These queries works, but does not give me customers without addresses:
Customer.includes(:orders, :shipping_address).where('customers.name LIKE ? or customers.mail LIKE ?', searchstring, searchstring)
Customer.where('customers.shipping_address_id = ?',2)
These attempts to adapt the above to give me customers without addreses doesn't:
Customer.includes(:orders, :shipping_address).where('shipping_address = ?', nil)
Customer.includes(:orders, :shipping_address).where('shipping_address = NULL')
# At the very least I should be able to get the right result by referencing the fk directly, but no?
Customer.where('customers.shipping_address_id = ?',nil)
What am I missing here?
The NULL value can be surprising until you get used to it. Conceptually, NULL means “a missing unknown value” and it is treated somewhat differently from other values.
You cannot compare null using equal to for this you must use IS NULL. So update your queries to
Customer.includes(:orders, :shipping_address).where('customers.shipping_address_id IS NULL')
Or rails way of doing this is
Customer.where(shipping_address_id: nil).includes(:orders, :shipping_address)
You could also just do:
#customers_without_shipping_ids = Customer.where('shipping_address_id IS NULL').all
Please have a try with these queries
Customer.all(:conditions => ['shipping_address_id IS NULL'])
and
Customer.includes(:orders, :shipping_address).where('shipping_address_id IS NULL')
Related
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")
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']
I'm trying to get all the clients that have doctors associated BUT none of them has started their first session (one client has_many doctors and can have first sessions with each of them).
So far I have:
#clients = Client.joins(:doctors).where('doctors.first_session IS NULL').order('clients.id DESC')
But this doesn't work when a client has for example 2 doctors. the first doctor.first_session = null but the second one is not. This case will return the client and it don't want it to.
Any ideas?
This is one of those cases where in order to find records that don't meet a certain condition, you do it by finding all records except those that meet the condition. In SQL this is done with a subquery in the WHERE clause.
For cases like this, the squeel gem is extremely helpful, because it encapsulates the SQL complexity. This is how I would do it (with squeel):
scope :visited_doctor, joins(:doctors).where { doctors.first_visit != nil }
scope :not_visited_doctor, where { id.not_in(Patient.visited_doctor.select(:id)) }
Note that you can do this without squeel, but you'll have to get your hands (and your code) dirty with SQL.
This will work, but may be a little less efficient since it does some of the work in ruby instead of all in the db.
clients = Client.order('clients.id DESC').include(:doctors).select do |client|
client.doctors.all? {|doctor| doctor.first_session.nil? }
end
Logically, that should fetch all the clients, and then in ruby, the select will evaluate the condition in the block and those clients that return true will be assigned to clients.
The condition block will return true only if all of that client's doctors have a nil first_session.
Hope that helps. There's probably a more efficient way to do this using subselects, but the syntax for that is likely to depend on which database you're using.
Well, I found a solution that involved two queries.
avoid_ids_results = Doctors.select('client_id')
.where("first_session IS NOT NULL")
.map(&:client_id).join(', ')
#clients = Clients.
joins(:doctors).
where('clients.id NOT IN (' + avoid_ids_results + ')').
order('clients.id DESC')
Thank you all!
You could create a method in your Client model which returns true if any first_session on a client's doctors is true, something like...
def has_first?
self.doctors.each do |doctor|
return true if !doctor.first_session.nil?
end
return false
end
This is pseudocode and may need to be tweaked first
I am trying to return all groups created by a user. All of the groups are associated with the user id. When I run a find_by query it only returns the first result. Is there a way for it to return multiple?
Thanks in advance
I'm writing a separate answer because I can't comment on James Lowrey's answer as I don't have 50 points.
find_all_by is deprecated (Ruby 4.2).
To get a list of active records from models, do:
Model.where(attribute_name: val)
For example, to find all records in Vehicle table (having column name "model_name") such that the value of model_name is "Audi", do
#vehicles = Vehicle.where(model_name: "Audi")
You can iterate through these like so:
<% #vehicles.each do |vehicle| %>
Change find_by to find_all_by and it will return all matching results.
I think find_all_by may be deprecated now (at least, I couldn't get it to work). I believe the 'where' function is now recommended
where("name LIKE ?","%#{search}%")
where(instructor_id: params[:choosen_instructor_id])
where ("id = ?",id_val)
In case you didn't know, the ? and parameter list is to prevent SQL injections
User class has id as primary key.
which is stored as user_id in Group class
Then to find all groups associated with that user could be found as.
#groups=Group.find_all_by_user_id(user_id)
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