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

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

Related

Count total number of records in Rails join table

I have two models, users and departments, and a join table users_departments to enable a has_and_belongs_to_many association between them. I am using PostgreSQL as the database.
# users table columns
id
name
# departments table columns
id
name
# users_departments table columns
user_id
department_id
What is the best way in Rails for counting the total number of records in the users_departments table? Preferably without creating a new model class.
Please note that I do not want to count the records for a specific user or department (user.departments.count / departments.users.count), but the total number records for the table, considering all users and departments.
The best way is to just create a model called UsersDepartment and do a nice and easy query on that.
count = UsersDepartment.count
You can query the table directly however with exec_query which gives you an ActiveRecord::Result object to play with.
result = ActiveRecord::Base.connection.exec_query('select count(*) as count from users_departments')
count = result[0]['count']

Regenerate ids of existing records

I have a Rails app with a custom algorithm for id generation for one table. Now I decided to use default incremental ids generated by Postgres as primary keys and move my custom values from id to another column like uid. And I want to regenerate values in id column for all records - as normal from 1 to n.
What is the best way to do this? I have about 1000 records. Records from other tables are associated with these records.
You can keep whatever value is in ID column but create a new column named UID and set it as a primary key and auto increment
def self.up
execute "ALTER TABLE mytable modify COLUMN uid int(8) AUTO_INCREMENT"
end
You can tell your model to use UID as primary key as
self.primary_key = 'uid'
You can simply do it by iterating on your records, and updating them (and their associated objects). 1000 records is not that much to process.
Let's say that you have a table named "my_objects", with its model named "MyObject". Let's also say that you have another table, named "related_objects" and its model "RelatedObject"
You can iterate on all your MyObjects records, and update their related objects and the record itself at the same time.
records = MyObject.all #Whatever "MyObject" you have.
i = 0
records.each do |record|
#Updating whatever associated objects the record have
record.related_objects.each do |related_object|
related_object.update_column("my_object_id", i)
end
#Updating the record itself
record.update_column("id", i)
i++
end

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.

How to sort by an associated column in this active record query

I need a few queries sorted by an associated model. I have a list of Customers that I get and I need to make sure the customer list is sorted by the last Message they received. Here are the current queries:
#open_customers = #company.customers.open.includes(:last_received_message)
#your_customers = current_user.customers.includes(:last_message)
#sidebar_customers = current_company.customers.open_or_claimed.
where("user_id = ? OR user_id IS NULL", current_user.id).
order(aasm_state: :asc).includes([:last_received_message, :user])
these are three separate queries.
#open_customers needs to be sorted by the created_at of last_received_message
#your_customers needs to be sorted by the created_at of last_message
#sidebar_customers needs to be sorted by the created_at of last_received_message
thanks!
You might try checking out Section 14: scopes here: http://guides.rubyonrails.org/active_record_querying.html
Also this website has a course called Rails 4 Outlaws that does a great job teaching scopes: https://www.codeschool.com

How do I get an array of unique values in my controller that is NOT connected to a model?

I have a table named Donations which has a column named season. Season contains the actual season the donation was made in... like 2011 or 2010, etc.
I also have a controller named ReportController that would like to pass a unique list of seasons from the Donations table.
In the ReportController, how do I get an array of those unique values? Is there something like #valid_seasons = Donations.find(:all).unique{|x| x.season} that I use in my reportcontroller? Will I then be able to pass #valid_seasons as an option for select statement in the views/report/foo.html.erb file?
You can use uniq_by
Donations.all.uniq_by{|x| x.season}
However this still executes a select * on your table.
You might be better off with using raw sql. Something like:
Donations.find_by_sql("SELECT * FROM donations GROUP BY season")
The first example will retrieve all the records and then filter. The second will only fetch the first row for each unique season.
You don't mention if this is rails 3 but, if so, this should do the trick:
Donations.select(:season).group(:season)
This will execute a proper group by:
SELECT season FROM "donations" GROUP BY season

Resources