Reputation: 15374
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
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
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