Rails eager load association with selected attributes - ruby-on-rails

Can anyone tell me if it's possible to eager load an association but only return specific attributes?
I'd like to retrieve some orders with their accounts but only require the account names.
Order.select([:id, :account_id]).includes(:account).limit(2)

I think jvnill's comment says it all:
I'm not sure that is possible. You can however add the account_name to the returned order records.
orders = Order.joins(:account).select('orders.id, orders.account_id, accounts.name AS account_name')
then just use account_name like orders.first.account_name

Related

"Index" page to display all items associated with current_user using '.where' but result is ActiveRecord, and I need to run each do on it

Sorry for the long title, I wanted to make sure I was being as specific as possible. This is my first question so please be patient!
I am building an index page that displays all the items in the consultations model that are associated with the current user. This used to be easy when I set #consultations = Consultation.where(user_id: current_user.id) in my controller. However, because consultations should be able to have more than one consultant assigned to each one, I changed the Consultation.user_id field to be a string array (I wasn't able to change to an integer array). I also connected the User and Consultation models via has_and_belongs_to_many and a join table.
I am now trying to query them with #consultation = Consultation.where {|a| a.user_id == ['current_user.id']} so that I can display all consultations in which the Consultation.user_id array contains the current_user.id.
This works as expected in pry, but on the actual view page I'm getting an error: NoMethodError: undefined method /'each/' for #<ActiveRecord::QueryMethods::WhereChain:0x007f82c23fe840>.
I understand that this is to be expected, since .where returns an ActiveRecord, which does not support methods such as each do, which is what I'm using on the index page to show all the consultations.
Any idea on how I can properly display all the consultations associated with the current_user.id? Thanks in advance.
you can do it like
#consultations = current_user.consultations
use associations instead of query
BTW
#consultation = Consultation.where {|a| a.user_id == ['current_user.id']}
this will not work because 'current_user.id' is string, it isn't id
it means that you try find all consultations where user_id == 'current_user.id'.
Do you see what I mean?
It sounds like you have a many-to-many relationship between consultants and clients. You can solve this by having a join table in the middle that holds both the client_id and the consultant_id. This would be a 3rd model to the consultant model and client models that you already have. You shouldn't try to store arrays as fields in ActiveRecord. ActiveRecord is just helping you organize data that is being written to a database.
Once you have a join table with both foreign_id's you can easily set up has_many relationships for both the client and consultants and then a has_may_through association. Then you won't need to worry about any #where calls because you can just call the associations.
The problem is that the syntax where you pass a block to where is something that you've just made up. Because no actual arguments are passed to where you don't get an ActiveRecord::Relation
You could change relationship between consultation and users to be has many through. If that join model was called assignments, then you could write a query such as
Consultation.joins(:assignments).where(assignments: {user_id: current_user.id})
If you keep your current approach with a user_id array column then, assuming this is Postgres, you can use the array query methods:
Consultation.where("user_id #> ARRAY[?]", current_user.id)

Find last record for specific user (Rails)

I want to do something like Report.last, but instead of the last record entered, I want the last record that a specific user entered.
You are probably looking for something like
Report.where(created_by_id: user_id).last
where the key in the where clause is the foreign key in a reports table record to the association with the user. I'd have to know how your models associate reports with their creators to know the right syntax.
You need to include the user_id or some sort of user indicator to be able to get the last record for a specific user. You will need to post more information like the model for your users and reports. But I think you are looking for something like this:
Report.select([:user_id, :id, 'MAX(created_at)']).group(:user_id).limit(5)
user = User.where(:some_condition => "some_value").first
user.reports.last
This would work if user is a local variable representing an active record user and records would query its associated records and find the last one.
I assume you have model relationship between User & Report
user = User.first
user.reports.order("updated_at DESC").last

Active Record Where Clause For Relation In Model

I have two Models User and Site. The User has category like 'basic and premium'. The user has relation to sites one -> many (i.e one user can have more than one sites). Now i want to select sites of premium user. Can someone tell me how to use where clause in ActiveRecord to achieve this?
I want to select sites of premium user
This will do
User.includes(:sites).where('users.category = ?', 'premium')
Update
If sites also have categories like 'wordpress or joomla', how do i
apply where clause to select only wordpress sites of premium users
For that you need to tweak the query like this
User.includes(:sites).where('users.category = ? and sites.category = ?', 'premium','wordpress')
As you said that category is a column, so Rails automatically generates the following method for you:
User.find_by_category("basic")
If you do not want to use this, you can use where method, in which you have to send a key-value pair like following:
User.where(:category => "basic")
And when you have found a user with the category you desired, you can simply call sites on it to get all the associated sites with a particular user.
You can try this also:
#user_ids = User.where(category: 'premium').pluck(:id)
#sites = Site.where(user_id: #user_ids)

Order Rails Active Record by Count in Another Table

I have a comment model which has likes associated with it. I keep the likes in a separate table and the comment model has_many likes. However, I want to order the comments by most popular and I do not know how to do an active directory query to return the order I want. I have tried:
Comment.order(:likes.count)
This isn't working. Any advice?
This is working for me currently with Rails 5:
Comment.joins(:likes)
.select('comments.*, count(likes) as like_count')
.group('comments.id')
.order('like_count desc')
It even adds a like_count attribute to each returned comment, so you can call comment.like_count.
Try this:
Comment.joins(:likes).order('count(likes.*) desc')

Eager loading fetches all fields though select is explicitly specified

I have a query like this,
company.users.select("users.id, users.state").includes(:organization)
here I'm eager loading the association organization. I was expecting the attributes id and user_id to be fetched in the objects, but then I get all fields fetched.
Is this the way, rails behaves when we eager load or am I missing something here ?
In your case you will get all company users not organizations.
Eager loading means pre-loading the database rows. It will not fetch only attributes. It loads all rows associated.
For example:
comments = Comment.all(:select => "users.name,comment_text", :include => :user)
Here, it will not just load names from user table. It will get all users rows from the database. So you don't have to fire extra queries. And one more thing is when you use include select clause is ignored when you have attributes of included tables. For more info go through ryan bates rialscast on joins vs include : http://railscasts.com/episodes/181-include-vs-joins

Resources