weteamsteve
weteamsteve

Reputation: 189

Rails has_many through query, with two references aka using through table attribute

I am looking for a way to query a model based on children in a has_many through association.

I have these models

class User < ApplicationRecord
  has_many :members
  has_many :squads, through: :members
end

class Squad < ApplicationRecord
  has_many :members
  has_many :users, through: :members
end

class Member < ApplicationRecord
  belongs_to :user
  belongs_to :squad
end

I'm basically using the Member class to provide a relationship between User and Squad, so it can hold membership information such as role, position, number, .etc

The goal is to have the Member model store User membership info as it relates to any Squad. A User can be an owner of one squad, be a member of another, and not be a member of yet another squad.

I am trying to display a Join link in my index.html.erb for all User's that do not have any member connection to a squad.

Currently, working with

<% @squads.each do |squad| %>
  <td><%= squad.name %></td>
  <% if Squad.includes(:members).where( 'members.user_id' => params[:users]).exists? %>
  <td><%= link_to 'Join', join_squad_path(:id => squad) %></td>
  <% end %>
<% end %>

with the primary line being

<% if Squad.includes(:members).where( 'members.user_id' => params[:users]).exists? %>

also tried stuff such as

I have an instance variable for each |squad| and have current_user.id available for the logged in user (using Devise)

Referencing Ruby on Rails Guide: Association Basics - the has many through association

Upvotes: 1

Views: 462

Answers (2)

CAmador
CAmador

Reputation: 1951

Do you want to show the button if the logged user is not a member of each squad? If so...

has_many association provides the method other_ids which returns an array of the associated objects' ids (in your case squad.user_ids). So you can check if the current user's id is in that array:

<% @squads.each do |squad| %>
  <td><%= squad.name %></td>
  <% unless squad.user_ids.include?(current_user.id) %>
  <td><%= link_to 'Join', join_squad_path(id: squad) %></td>
  <% end %>
<% end %>

Upvotes: 2

Thang
Thang

Reputation: 841

User.includes(:members).where(members: { id: nil }).or(User.includes(:members).where.not(members: { squad_id: squad.id }))

Explanation:

User.includes(:members).where(members: { id: nil })

To query users that have no member record (belong to no squad)

User.includes(:members).where.not(members: { squad_id: squad.id })

To query users that do have member record but not member of the target squad.

Upvotes: 2

Related Questions