In Rails display data from models with through relationships - ruby-on-rails

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> </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?

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>

Related

Displaying custom query results in View

I'm relatively new to Rails and in addition to displaying "All" items on my Index page, I also want to show a filtered list. Essentially a subset of records that have an association to another model.
My models are Issue and Split. A Split belongs to an issue and an issue has and belongs to many splits.
If a Split is associated with issue_id = 1, then I want it shown in the list of splits for that issue
Here is my controller code:
class SplitsController < ApplicationController
before_action :set_split, only: [:show, :edit, :update, :destroy]
# GET /splits
# GET /splits.json
def index
#splits = Split.all
#chosen_splits = Issue.find(1)
end
Here is the code I have in my index view:
<tbody>
<% #chosen_splits.each do |split| %>
<tr>
<td><input type="checkbox" value></td>
<td><%= link_to split.name, split_path(split) %></td>
<td class="text-right"><%= number_with_delimiter(split.quantity) %></td>
<td><%= link_to 'Edit', edit_split_path(split), :class => 'btn btn-xs btn-default' %></td>
<td><%= link_to 'Delete', split, method: :delete, data: { confirm: 'Are you sure?'}, :class => 'btn btn-xs btn-danger' %></td>
</tr>
<% end %>
</tbody>
Here is my Issue Model:
class Issue < ActiveRecord::Base
belongs_to :publication
has_and_belongs_to_many :splits
has_many :issue_split_geographies
belongs_to :medium
validates :name, :start_date, :status, presence: true
end
When I load the page I'm getting a "undefined method `each' for" error. But, the same basic logic is working for when I run the #splits variable.
All help is greatly appreciated.
You need
#chosen_splits = Issue.find(1).splits
Otherwise you will call .each method for your issue
Else please edit has_and_belongs_to_many :splits to just has_many :splits in your Issue model

undefined method `suburb' for nil:NilClass

I am getting the above error when trying to display the 'suburb' for all Vaults objects.
I have a Vault Model
class Vault < ActiveRecord::Base
belongs_to :user
has_one :address, dependent: :destroy
end
I have an Address Model
class Address < ActiveRecord::Base
belongs_to :vault
def to_s
"#{suburb}"
end
end
This is my index in my VaultsController
def index
#vaults = Vault.all
end
My Vaults view is as follows
<h1>Vaults</h1>
<table class="table">
<tr class="active">
<th>Location</th>
<th>Capacity</th>
</tr>
<% #vaults.each do |vault| %>
<tr>
<td><%= link_to vault.address.suburb, vault.address %></td>
<td><%= vault.capacity %></td>
</tr>
<%end%>
</table>
<%= link_to 'Create Vault', new_vault_path, class: 'btn btn-default btn-lg' %>
When I run the following command on the console it returns that correct field:
Vault.first.address.suburb

Rails children not rendering p

I have a model called Task Order that has_many Invoices. When I click "Show" for a Task Order, it is supposed to show all of the Invoices that belong to that Task Order. However, when I click "Show" it shows ALL of the invoices, even ones that do not belong to that task order. Note that I have the same relationship and views for my Contract/Task Order, but it is working correctly so I am not sure where I went wrong.
Here is my Task Order model:
class TaskOrder < ActiveRecord::Base
belongs_to :contract
has_many :invoices, :dependent => :destroy
validates_presence_of :id
validates_uniqueness_of :id
self.primary_key = :id
end
Here is my Invoice model
class Invoice < ActiveRecord::Base
belongs_to :task_order
validates_presence_of :task_order_id
end
Here is my views/task_orders/show code
Invoices:
<table>
<thead>
<tr>
<th>Invoice Date</th>
<th>Invoice #</th>
<th>PoP</th>
<th>Amount</th>
<th>Description</th>
<th>Invoice TO</th>
<th></th>
<th></th>
</tr>
</thead>
</tr>
<tbody>
<% #invoices.each do |invoice| %>
<tr>
<td><%= invoice.invoiceDate%></td>
<td><%= invoice.invoiceNumber %></td>
<td><%= invoice.PoP %></td>
<td><%= number_to_currency(invoice.amount) %></td>
<td><%= invoice.description %></td>
<td><%= invoice.task_order_id %></td>
<td><%= link_to 'Show', invoice %></td>
<td><%= link_to 'Edit', edit_invoice_path(invoice) %></td>
<td><%= link_to 'Destroy', invoice, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
And here is my Task Order controller:
def show
#invoices = Invoice.all
end
def index
#task_orders = TaskOrder.all
end
In your show method, you just want to get only the task order's invoices, rather than all invoices, which you are currently getting.
def show
#task_order = TaskOrder.find(params[:id])
#invoices = #task_order.invoices
end
This way, you don't need to change your show.html.erb file. In addition, you should take a look at the Rails Guides, which should aid you in your quest to learn Rails.

rails find_by: get the first item by adding the reference key as parameter

I'm new to Rails and I'm building a quizz application.
I have a has_many and belongs_to association set up between two models: Level and Question.
#models/level.rb
class Level < ActiveRecord::Base
has_many :questions
end
#models/question.rb
class Question < ActiveRecord::Base
belongs_to :level
attr_accessible :level_id
end
I have an action 'startlevel' in my LevelController that simply lists all the levels.
class LevelsController < ApplicationController
def startlevel
#levels = Level.all
end
and the view with links to go to the first question of the level. I want to add the id of the level as a parameter in the link. I noticed the 1 in the url of the view. I have no idea why how it came there and if it is part of my problem.
#controller/levels/startlevel/1
<h2>which level would you like to play</h2>
<table>
<tr>
<th>level</th>
</tr>
<% #levels.each do |level| %>
<tr>
<td> level <%=level.number %></td>
<td><%= link_to '<> play this level', :controller => "questions", :action => "answer",:level_id=> level.id%></td>
</tr>
<% end %>
</table>
When I follow the the link, I want to go to the first question with a level_id that matches the id parameter in the link_to, so i tried to do this:
class QuestionsController < ApplicationController
def answer
#question = Question.find_by_level_id(params[:level_id])
end
with this view
<p>
<b>Question:</b>
<%=h #question.word %>
</p>
<p>
<b>1:</b>
<%=h #question.ans1 %>
</p>
<p>
<b>2:</b>
<%=h #question.ans2 %>
</p>
<p>
<b>3:</b>
<%=h #question.ans3 %>
</p>
<p>
<b>4:</b>
<%=h #question.ans4 %>
</p>
<%= form_tag(:action => "check", :id => #question.id) do %>
<p>
<b>the correct answer is number: </b>
<%=text_field :ans, params[:ans]%>
</p>
<p><%= submit_tag("check")%></P>
<% end %>
unfortunately, whatever i tried, all i got for the last couple of hours was:
undefined method `word' for nil:NilClass
(word is an attribute of a question)
I want to cry. what am I doing wrong?
p.s. my idea is to add a link_to_unless in the 'answer'view which goes to the next question of the same level unless the next one is nil, so i think i need to group the questions with the same reference key somehow?
It works right now, however i'm not sure if this is the prettiest solution. Views/levels/play is empty since it only redirects to the first question of the level.
class LevelsController < ApplicationController
def startlevel
#levels = Level.all
end
def play
#level = Level.find(params[:id])
#question = Question.find_by_level_id(params[:id])
redirect_to controller: 'questions', action: 'answer', id: #question.id
end
#views/levels/startlevel
<h2>Which level would you like to play</h2>
<table>
<tr>
<th>level</th>
</tr>
<% #levels.each do |level| %>
<tr>
<td> level <%=level.number %></td>
<td>
<%= link_to '<> Play this level', :action => "play", :id=>level.id %></td>
</tr>
<% end %>
</table>
QuestionsController
class QuestionsController < ApplicationController
def answer
#question= Question.find(params[:id])
end
edit: Routes:
quizz::Application.routes.draw do
resources :questions
resources :levels
get "home/index"
root :to => 'home#index'
match ':controller/:action/:id', via: [:get, :post]
match ':controller/:action/:id.:format', via: [:get, :post]

Edit multiple saved records

I'm trying to develop a simple exercise log app, and I'm stuck (again). A user selects a category, and a specific workout, and I return a list of exercises belonging to that workout.
An effort is a user specific instance of an exercise.
class Exercise < ActiveRecord::Base
has_many :efforts
end
class Effort < ActiveRecord::Base
belongs_to :exercise
end
I'm retrieving the list of exercises in the efforts controller
class EffortsController < ApplicationController
def log_workout
#exercises = Exercise.where("category_id = ? AND workout_id = ?", params[:exercise][:category_id], params[:exercise][:workout_id])
#effort = Effort.new
end
end
The user logs their workout by using the following form
<%= form_tag save_workout_path, method: :put do %>
<table>
<tr>
<th>Exercise</th>
<th>Sets</th>
<th>Reps</th>
</tr>
<% #exercises.each do |exercise| %>
<%= fields_for "efforts[]", #effort do |f| %>
<tr>
<td><%= exercise.name %></td>
<td><%= f.number_field :sets %></td>
<td><%= f.number_field :reps %></td>
<%= f.hidden_field :exercise_id, :value => exercise.id %>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag "Log it" %>
<% end %>
class EffortsController < ApplicationController
def create
params[:efforts].each do |values|
if current_user.efforts.create(values)
flash[:notice] = 'Efforts were successfully saved.'
else
render action: 'new'
end
end
end
end
How right this is, I'm not sure, but it works. My problem now is trying to retrieve saved 'efforts' and allowing them to be modified through the same form. (Letting the user edit their workout log). Would appreciate any guidance/help

Resources