Guilherme Nunes
Guilherme Nunes

Reputation: 175

Get two queries in one - Rails ActiveRecord

I've been struggling, and couldn't find the right answers by myself.

For example, I have two separated associations

Profile that belongs_to User

Comment that belongs_to User

Both Profile and Comment have a user_id foreign key

Through Comment I can easily access user like Comment.first.user for example. But I can't do like Comment.first.user.profile (How can I do this?) Can I join the results in a single query just with the user_id? Like Comment.joins .. ? I just want to know if this is possible, and if I can get some references I can do a research.

For example, I have this query for User.find(1)

id:12 | email:[email protected]

And I have this query for User.find(1).profiles

name: Fire | lastname: Fox | id_user: 12

Is it possible to obtain a result like this in ActiveRecord?

email:[email protected] | name: Fire | lastname: Fox

Also, can I do this with .all, instead of with .find or .where?

Comment model

class Comment < ApplicationRecord
  belongs_to :user
end

Profile model

class Profile < ApplicationRecord
  belongs_to :user
end

User model

class User < ApplicationRecord
  has_one :profile
  has_many :projects
  has_many :comments
  accepts_nested_attributes_for :profile
end

Upvotes: 0

Views: 510

Answers (1)

Deepak Mahakale
Deepak Mahakale

Reputation: 23661

Sol 1: If you want to fetch it in one query

You need to join Profile through User and you can query like this

Comment.joins(user: :profile)
  .select('users.email', 'profiles.name', 'profiles.lastname')
  .where(id: 123)

Sol 2: You just need to add a through association

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :profile, through: :user
end

and now you can access it like

comment = Comment.first
comment.user.email        #=> "[email protected]"
comment.profile.name      #=> "Fire"
comment.profile.lastname  #=> "Fox"

You can also use delegate but that will fire 2 queries

class User < ApplicationRecord
  has_one :profile
  has_many :projects
  has_many :comments
  accepts_nested_attributes_for :profile

  delegate :name, :lastname, to: :profile, allow_nil: true
end

And now you can directly call name and lastname on user

comment = Comment.first
comment.user.email        #=> "[email protected]"
comment.user.name         #=> "Fire"
comment.user.lastname     #=> "Fox"

Upvotes: 2

Related Questions