Jake
Jake

Reputation: 1370

In Rails display data from models with through relationships

I'm struggling to display only the RELEVANT data in a table that is using has_many and through relationships. My models are the following:

Models

class TrainingResource
  has_many :user_training_resources, dependent: :destroy
end

class UserTrainingResource
  belongs_to :user
  belongs_to :training_resource
end

class Users
  has_many :user_training_resources, dependent: :destroy
  has_many :training_resources, through: :user_training_resources
end

Ultimately I'm trying to build out a table on the Training Resource Show page of those users that have THAT Training Resource and their current status along with the ability for the user to delete said resource (User Training Resource).

So example while looking at Alpha Training Resource the user sees of the Training Resource: Name, Description, URL, and Total Subscriptions. Then below a list of the users that have Alpha Training along with their current status AND the option to delete it.

Controller

class Admin::TrainingResourcesController < Admin::ApplicationController
  belongs_to_app :training_resources

  add_breadcrumb 'Training Resources', :admin_training_resources_path

  before_action :load_training_resource, only: [:show, :edit, :update, :destroy]

  respond_to :html, :json

  def show
    @user_training_resources = UserTrainingResource.all
    @users = User.all
    respond_with(@training_resource)
  end

  private

  def load_training_resource
    @training_resource = TrainingResource.find_by!(id: params[:id])
  end
end

My Training Resource Show template looks like:

<dl class="dl-horizontal">
  <dt>Name:</dt>
  <dd><%= @training_resource.name %></dd>

  <dt>Description:</dt>
  <dd><%= @training_resource.description %></dd>

  <dt>Subscriptions Available:</dt>
  <dd><%= @training_resource.subscriptions_available %></dd>

  <dt>Total Subscriptions:</dt>
  <dd><%= @training_resource.total_subscriptions %></dd>

  <dt>Url:</dt>
  <dd><%= @training_resource.url %></dd>
</dl>

<div class="table-responsive">
  <table class="table table-striped table-hover">
    <thead>
      <tr>
        <th>Name</th>
        <th>Training Resource Names</th>
        <th>Status</th>
        <th>&nbsp;</th>
      </tr>
    </thead>
    <tbody>
      <% @users.all.each do |user| %>
        <tr>
          <td><%= user.full_name %></td>
          <td><%= user.training_resources.map(&:name).join(', ') %></td>
          <td><% user.user_training_resources.each do |user_training_resource| %></td>
            <td><%= user_training_resource.status %></td>
          <% end %>
          <td class="table-actions">
            <%# <%= link_to 'Delete', admin_user_training_resource_path(@user_training_resource), :method => :delete, :data => {:confirm => 'Are you sure you want to delete this Training resource?'}, :class => 'btn btn-danger btn-sm' %> %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

So if I go to Training Resource and click on the show for Alpha I see it's name, description, total subscriptions, and url. However the table below will show me all users, all their training resources, and then their status. Not exactly what I want.

I've tried doing something like below in hopes of just going through Training Resource:

<% @training_resource.each do |training_res| %>
  <%= training_res.name %>
<% end %>

This results in undefined method 'each'. So how do I display ONLY the data associated with the TrainingResource?

Upvotes: 0

Views: 26

Answers (1)

Jagdeep Singh
Jagdeep Singh

Reputation: 4920

Add a new association for users in model TrainingResource, so that you can directly fetch all the users for a training_resource record.

class TrainingResource
  has_many :user_training_resources, dependent: :destroy
  has_many :users, through: :user_training_resources
end

Change your controller action show to look like below:

def show
  respond_with @training_resource
end

And display the users inside <tbody> tag on training_resource show page in the following way:

<% @training_resource.users.each do |user| %>
  <tr>
    <td><%= user.full_name %></td>

    <!-- If you want to display all the training_resources of the user and their statuses -->
    <td><%= user.training_resources.map(&:name).join(', ') %></td>
    <td><%= user.user_training_resources.map(&:status).join(', ')</td>

    <td class="table-actions">
      <!-- Assuming your path is something like '/admin/training_resources/:id/users/:user_id' -->
      <%= link_to 'Delete', admin_user_training_resource_path(@training_resource, user), method: :delete, data: { confirm: 'Are you sure you want to delete this Training resource?' }, class: 'btn btn-danger btn-sm' %>
    </td>
  </tr>
<% end %>

This code is not tested. So, please let me know, if you face any errors.

Update

If you want to show the status of only the current training_resource for all the users, do:

<%- utr = user.user_training_resources.where(training_resource: @training_resource).first %>
<td><%= utr.status %></td>

Upvotes: 1

Related Questions