Richlewis
Richlewis

Reputation: 15374

Scope on following association

I am trying to get back into using my scopes again, encountering some issues. I have the following 3 models

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable
  has_one :profile
  has_many :campaigns
end

class Profile < ActiveRecord::Base
  belongs_to :user
end

class Campaign < ActiveRecord::Base
  belongs_to :user
end

I would like to be able to list all users who have created a campaign, though if they have created more than one I only want one instance of that user returned, I would also like to be able to access that users profile info..

I did come up with

scope :users_with_campaign, ->() {
  joins(:campaigns).where.not('campaigns.user_id' => nil) 
}

However that returns multiple instances of a user if i do this in my view for example

<% @user_campaigns.each do |u| %>
    <%= u.email %>
  <% end %> 

If anyone could advise how to get access to a users profile and get only one instance of that user returned that would be much appreciated, could i use the .uniq method maybe with this?

Thank You

Upvotes: 0

Views: 42

Answers (2)

edikgat
edikgat

Reputation: 869

note you don't need 'where' case, because you use request will be translated to 'inner join' here

scope :users_with_campaign, -> {
  joins(:campaigns).uniq
}

scope :with_profile, -> { joins(:profile).uniq }

and then use

User.users_with_campaign.with_profile.uniq

that will make only one request and you can access to user profile like

user.profile

this will not make one more request, becouse rails will cach result from first request

P.S note that this request will take only users that have profile, if you want to take all users, you should use 'includes' instead of 'joins'

Upvotes: 1

j-dexx
j-dexx

Reputation: 10406

scope :users_with_campaign, ->() {
  includes(:profile).joins(:campaigns).where.not('campaigns.user_id' => nil) 
}

Should work. Then you can do

<% @user_campaigns.each do |u| %>
  <%= u.email %>
  <%= u.profile.field %>
<% end %> 

Or you could delegate the field you're trying to access

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable
  has_one :profile
  has_many :campaigns
  delegate :field, to: :profile
end


<% @user_campaigns.each do |u| %>
  <%= u.email %>
  <%= u.field %>
<% end %> 

Or you can prefix it with profile if that makes more sense

delegate :field, to: :profile, prefix: true

<% @user_campaigns.each do |u| %>
  <%= u.email %>
  <%= u.profile_field %>
<% end %> 

Upvotes: 1

Related Questions