How to use association with find_by_sql in rails? - ruby-on-rails

I have a long SQL query, which i am using in rails Model.find_by_sql, I have to add couple of conditions in that query like i wanted to fetch all the records whose parent.is_allowed is true.
That means i am fetching all the child elements and i wanted to use association which is between child and parent.And in the Child table we have the parent_id.
Thanks

You could try something like this:
Model.find_by_sql("select * from models where parent_id in (select id from parents where is_allowed='true') and ... ")
Just replace the ... with your original SQL query.
Edit
Based on your comment, I think this line is more what you need:
Model.find_by_sql("select * from models where parent_id in (select id from users where is_allowed='true')")

Related

Retrive records which are not referenced in other table, ActiveRecord query

There are 2 tables : User and Teacher. Teacher.user_id is from User. So, how do I find in a single query, all the users who are not in teachers.
I meant something along the lines :
User.not_in(Teacher.all)
You can use where.not query from ActiveRecord try something like below:
User.where.not(id: Teacher.pluck(:user_id).reject {|x| x.nil?})
Note: used reject method, in case you have nil values in some records.
The other users seem to have neglected the rails 3 tag (since removed based on the approved answer. My answer left for posterity) : Please try this
User.where("id NOT IN (?)",Teacher.pluck(:user_id).join(","))
This will become SELECT * FROM users WHERE id NOT IN (....) (two queries one to get the user_id from teachers and another to get the user(s) not in that list) and may fail based on the size of teacher table.
Other option is an arel table:
users = User.arel_table
User.where(users[:id].not_in(Teacher.select(:user_id).where("user_id IS NOT NULL")))
This should produce a single query similar to
SELECT * FROM users
WHERE id NOT IN ( SELECT user_id FROM teachers WHERE user_id IS NOT NULL)
(one query better performance) * syntax was not fully tested
Another single query option might be
User.joins("LEFT OUTER JOIN teachers ON teachers.user_id = users.id").
where("teachers.user_id IS NULL")
I think you should be able to do something like this
User.where.not(id: Teacher.ids)

Clean and concise way to find active records that have the same id as another set of active records

I have a table called shoppers and another table called Users. I have a shopper_id which is the foreign key in the Shoppers table and refers to the primary key id in the Users table.
I ran a query called #shoppers = shoppers.where("some condition")
This allowed me to get a set of shoppers who satisfy the condition. Next I would like to select those Users who have the same id as the shopper_id as the individual objects in #shoppers.
I know I could do this by writing a loop, but I am wondering if ruby on rails allows me to write a Users.where condition that can help me obtain the subset of user objects with the same id as shopper_id arranged in ascending order by the name field in the Users table.
Any ideas?
Try this.
#shoppers = Shopper.where("some condition")
#users = User.where(id: #shoppers.collect(&:shopper_id)).order('name asc')

Count, empty? fails for ActiveRecord with outer joins

I have two models, Monkey and Session, where Monkey has_many Session. I have a scope for Monkey:
scope :with_session_counts, -> {
joins("LEFT OUTER JOIN `sessions` ON `sessions`.`monkey_id` = `monkeys`.`id`")
.group(:id)
.select("`monkeys`.*, COUNT(DISTINCT `sessions`.`id`) as session_count")
}
in order to grab the number of associated Sessions (even when 0).
Querying #monkeys = Monkey.with_session_counts works as expected. However, when I test in my view:
<% unless #monkeys.empty?%>
I get this error:
Mysql2::Error: Column 'id' in field list is ambiguous:
SELECT COUNT(*) AS count_all, id AS id FROM `monkeys`
LEFT OUTER JOIN `sessions` ON `sessions`.`monkey_id` = `monkeys`.`id`
GROUP BY `monkeys`.`id`
How would I convince Rails to prefix id with the table name in presence of the JOIN?
Or is there a better alternative for the OUTER JOIN?
This applies equally to calling #monkeys.count(:all). I'm using RoR 4.2.1.
Update:
I have a partial fix for my issue (specify group("monkeys.id") explicitly) I wonder whether this is a bug in the code that generates the SELECT clause for count(:all). Note that in both cases (group("monkeys.id") and group(:id)) the GROUP BY part is generated correctly (i.e. with monkeys.id), but in the latter case the SELECT only contains id AS id. The reason I say 'partial' is because it works in that it does not break a call to empty?, but a call to count(:all) returns a Hash {monkey_id => number_of_sessions} instead of the number of records.
Update 2:
I guess my real question is: How can I get the number of associated sessions for each monkey, so that for all intents and purposes I can work with the query result as with Monkey.all? I know about counter cache but would prefer not to use it.
I believe it is not a bug. Like you added on your update, you have to specify the table that the id column belongs to. In this case group('monkeys.id') would do it.
How would the code responsible for generating the statement know the table to use? Without the count worked fine because it adds points.* to the projection and that is the one used by group by. However, if you actually wanted to group by Sessions id, you would have to specify it anyway.

Rails 3 Comparing foreign key to list of ids using activerecord

I have a relationship between two models, Registers and Competitions. I have a very complicated dynamic query that is being built and if the conditions are right I need to limit Registration records to only those where it's Competition parent meets a certain criteria. In order to do this without select from the Competition table I was thinking of something along the lines of...
Register.where("competition_id in ?", Competition.where("...").collect {|i| i.id})
Which produces this SQL:
SELECT "registers".* FROM "registers" WHERE (competition_id in 1,2,3,4...)
I don't think PostgreSQL liked the fact that the in parameters aren't surrounded by parenthesis. How can I compare the Register foreign key to a list of competition ids?
you can make it a bit shorter and skip the collect (this worked for me in 3.2.3).
Register.where(competition_id: Competition.where("..."))
this will result in the following sql:
SELECT "registers".* FROM "registers" WHERE "registers"."competition_id" IN (SELECT "competitions"."id" FROM "competitions" WHERE "...")
Try this instead:
competitions = Competition.where("...").collect {|i| i.id}
Register.where(:competition_id => competitions)

Active Record "where" query from parent resource

I need to create a Query that evaluates if the parent object has receives at least two likes. If he has, then include it in the random query.
I tried something like this but it didn't work.
#attachments = Attachment.joins('LEFT OUTER JOIN users ON users.id = attachments.user_id').where("received_likes_count > ?",2).order("random()")
Does this work for you? I'm envisioning your User is the parent, and the attachments table has a user_id, but I'm not entirely sure based on your wording of the question.
The main trick of this is it uses a sub-select to gather ids for use in the IN clause.
#attachments = Attachment.where(
'user_id IN (
SELECT id FROM users WHERE received_likes_count > ?
)', 2
).order('random()')
MySQL?
#attachments = Attachment.joins(:users).where("received_likes_count > ?",2).order("rand()")

Resources