Search code examples
sqlruby-on-railsrubyruby-on-rails-5

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

  • User.includes(:squads, :members).where('squads.id = ? AND members.users = ?', squad, current_user)

  • u = squad.users.includes(:member).where('member.user = ?', current_user)

  • Member.where.not("squad = #{squad.id}").find(user: current_user.id)

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


Solution

  • 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 %>