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.
Related
I am new to Ruby and RubyOnRails. I have been following a basic Rails tutorial thus far and have created several views and controllers to be able to perform basic CRUD on my MySQL DB, each one is specific to tables in the DB.
I started a new view, and I want to be able to display info from two separate tables. I want to be able to grab the Customers Name for their contract. I feel like this is an easy and common fix, What the heck am I overlooking?
Contract View
<table>
<tr>
<th>Contract ID</th>
<th>Customer ID</th>
<th>Discount</th>
<th>Start Date</th>
<th>End Date</th>
<th>Payment Terms</th>
<th>Delivery Day Of Week</th>
<th>Employee ID</th>
<th>Note</th>
<th>Commission</th>
<th>Active</th>
</tr>
<% #contracts.each do |contract| %>
<tr>
<td><%= contract.ContractID %></td>
<td><%= contract.CustomerID %></td>
<td><%= contract.fields_for :customer do |w| %>
<%= w.text_field :CustomerName %>
<% end %>
</td>
<td><%= contract.Discount %></td>
<td><%= contract.StartDate %></td>
<td><%= contract.EndDate %></td>
<td><%= contract.PaymentTerms %></td>
<td><%= contract.DeliveryDayOfWeek %></td>
<td><%= contract.EmployeeID %></td>
<td><%= contract.Note %></td>
<td><%= contract.Commission %></td>
<td><%= contract.Active %></td>
</tr>
<% end %>
</table>
Contract Model
> class Contract < ApplicationRecord belongs_to :customer
>
> accepts_nested_attributes_for :customer
> #Validation
>
>
> #Mapping this object to the Database tables self.table_name = "contract" self.primary_key = "ContractID" end
Customer Model
> class Customer < ApplicationRecord
>
> has_many :contracts
>
> #Validation validates :CustomerID, :CustomerTypeID, presence: true
>
> validates :CustomerID, uniqueness: true
>
> #Mapping this object to the Database tables self.table_name = "customer" self.primary_key = "CustomerID"
>
> end
Contracts Controller
class ContractsController < ApplicationController
def index
#contracts = Contract.all
#customers = Customer.all
end
end
Since you've already defined that a Customer may have many contracts then you need now to define that that Contract belongs to a customer, so, modifying your models they should look like:
class Contract < ApplicationRecord
belongs_to :customer
...
end
class Customer < ApplicationRecord
has_many :contracts
...
end
Now you're able to access the customer name attribute from a certain contract, like:
<% #contracts.each do |contract| %>
<%= contract.customer.name %>
<% end %>
This should work on getting the customer name, but for improving that query, you might add an includes on the index action:
def index
#contracts = Contract.includes(:customer).all
...
end
I have a loop using associations. I'm looking to group by treatment and display in a row.
Each loop has three records for each treatment. The code below this is what i'm producing.
VIEW
<table>
<tr>
<td>Treatment</td>
<td>Date</td>
<td>Count</td>
</tr>
<% #trial.establishmentMethods.order(:treatment_selection_id).each do |data| %>
<tr>
<td><%= data.treatmentSelection.treatment.name %></td> This is reference by treatment_selection_id.
<td><%= data.date %></td>
<td><%= data.count %></td>
</tr>
<% end %>
</table>
This is what i'm hoping to produce. Display the treatment once, then loop the related treatment_selection_id's on the same row.
Here are my models and associations.
class Trial < ApplicationRecord
has_many :assessments, primary_key: 'trial_id'
has_many :establishmentMethods, through: :assessments
end
class EstablishmentMethod < ApplicationRecord
belongs_to :treatmentSelection, primary_key: 'treatment_selection_id', foreign_key: 'treatment_selection_id'
has_many :treatments, through: :treatmentSelection
end
class TreatmentSelection < ApplicationRecord
belongs_to :treatment, primary_key: 'treatment_id'
end
It seems like TreatmentSelection has_many establishmentMethods, so you should add that to the TreatmentSelection model. Then you can do something like:
<% treatment_selections.each do |treatment_selection| %>
<tr>
<td><%= treatment_selection.treatment.name %></td>
<% treatment_selection.establishmentMethods.each do |em| %>
<td><%= em.date %></td>
<td><%= em.count %></td>
<% end %>
</tr>
<% end %>
By the way, it's convention to use snake_case in ruby and it will make using associations easier.
I want to set up sort order for active record collection proxy in table.
It should be sorted by number of available rooms (from highest to lowest).
The trick is that #rooms.reserved is a boolean and to calculate quantity of free/reserved rooms I have to use helper method to avoid record collection proxy errors. I get proper results, but I need to sort table by number of available rooms.
I have two models: Room and Hotel.
class Room < ApplicationRecord
belongs_to :hotel, optional: true # avoiding rails 5.2 belongs_to error
accepts_nested_attributes_for :hotel
end
and
class Hotel < ApplicationRecord
has_many :rooms, dependent: :destroy
accepts_nested_attributes_for :rooms
end
I have table:
<table>
<tr>
<th>Name</th>
<th>Rooms count</th>
<th>Rooms status: in reserve || free</th>
</tr>
<% #hotels.each do |hotel| %>
<tr>
<td><%= hotel.name %></td>
<td><%= hotel.rooms_count %></td>
<td><%= rooms_reservation_status(hotel.rooms) %></td> <!-- rooms_reservation_status helper method in application_helper.rb -->
<td ><%= link_to 'Show', hotel_path(hotel) %></td>
<td><%= link_to 'Destroy', hotel, method: :delete, data: { confirm: 'Are you sure?' } %>
</tr>
<% end %>
</table>
Helper method
# rooms_reservation_status iterates throught ActiveRecord::Associations::CollectionProxy
# and calculates the sum of free rooms aswell as a sum of reserved rooms
def rooms_reservation_status(rooms)
reserved = 0
free = 0
rooms.each do |r|
r.reserved == true ? reserved+=1 : free+=1
end
"#{reserved} || #{free}"
end
Active Record table for rooms:
class CreateRooms < ActiveRecord::Migration[5.1]
def change
create_table :rooms do |t|
t.boolean :reserved, :default => false
t.belongs_to :hotel, index: true
t.timestamps
end
end
end
I would add a class method on the Room model in order to return for a given collection the number of free rooms and reserved rooms:
class Room < ApplicationRecord
belongs_to :hotel, optional: true
accepts_nested_attributes_for :hotel
def self.reserved_count
where(reserved: true).count
end
def self.free_count
where(reserved: false).count
end
end
Once you have implemented, you can call it from the relationship declared in Hotel model:
class Hotel < ApplicationRecord
has_many :rooms, dependent: :destroy
accepts_nested_attributes_for :rooms
def reserved_rooms
rooms.reserved_count
end
def free_rooms
rooms.free_count
end
end
Your view will look finally like this:
<table>
<tr>
<th>Name</th>
<th>Rooms count</th>
<th>Rooms status: in reserved || free</th>
</tr>
<% #hotels.each do |hotel| %>
<tr>
<td><%= hotel.name %></td>
<td><%= hotel.rooms_count %></td>
<td><%= "#{hotel.reserved_rooms} || #{hotel.free_rooms}" %></td>
<td ><%= link_to 'Show', hotel_path(hotel) %></td>
<td><%= link_to 'Destroy', hotel, method: :delete, data: { confirm: 'Are you sure?' } %>
</tr>
<% end %>
</table>
Sorting the Hotels in your controller
In your controller make sure that you eager load Rooms for Hotel:
#hotels = Hotel.includes(:rooms).sort_by { |h| h.free_rooms.to_i }.reverse
You could eventually implement it as Hotel.includes(:rooms).sort_by(&:free_rooms).reverse.
In this way you won't need any join or helper.
Regarding your comment, free_rooms is implemented as an instance method (e.g. Hotel.first.free_rooms), so it will not be available for an ActiveRecord_Relation (e.g. Hotel.all.free_rooms)
Good day all,
Pardon me for my noob-ness in rails.
So here's my question.
So I've a category model and a itinerary model defined below
class Category < ActiveRecord::Base
has_many :categorizations, :dependent => :destroy
has_many :itineraries, :through => :categorizations
end
class Itinerary < ActiveRecord::Base
has_many :categorizations
has_many :categories, :through => :categorizations
end
So in my view, I am looping through categories to display itineraries in groups.
<% #categories.each do |category| %>
<table>
<thead>
<tr>
<th colspan="4"><%= category.name %></th>
</tr>
</thead>
<tbody>
<% category.itineraries.each do |itinerary| %>
<tr>
<td><%= itinerary.name %></td>
<td><%= link_to 'Show', itinerary %></td>
<td><%= link_to 'Edit', edit_itinerary_path(itinerary) %></td>
<td><%= link_to 'Destroy', itinerary, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
So I am wondering, how do we display itineraries that are not categorised yet?
I've searched around and found out that using scopes in the model will be the way to go.
scope :without_categories, -> { includes(:categorizations).where( :categorizations => { :itinerary_id => nil } )}
I find it not very "DRY" due to the fact that I've to write another table to iterate through itinerary.without_categories again.
Is there a way where we're able to code it in such a way where categories.all shows everything with uncategorized items in it?
Thank you.
Update #1
Decided to use this in my controller, which builds a new "Uncategorized" category on index action and it'll add to the array.
def index
uncategorized = Category.new
uncategorized.name = "Uncategorized";
uncategorized.itineraries = Itinerary.without_categories
#categories = Category.all << uncategorized
end
I know that in rails, controllers should be as skinny as possible.
But I can't think of a better way.
Anyone with a better answer, please feel free to share. Thanks! :)
You just have to find the itineraries that dont have a reference inside the Categorizations table. You can do a nested query for this.
SELECT * FROM itineraries where id NOT IN ( SELECT itinerary_id FROM categorizations')
just do a method in your Itinerary model like this:
def self.uncategorized
Itinerary.find_by_sql('SELECT * FROM itineraries where id NOT IN ( SELECT itinerary_id FROM categorizations)')
end
I have this in the index view:
<% #submissions.each do |submission| %>
<tr>
<td><%= submission.id %></td>
<td><%= User.find_by_id(submission.user_id).name.to_s %></td>
</tr>
<% end %>
I know I am not supposed to use find_by in the view.
How can I move this to the controller (or model)?
I tried to insert this in the index method of my submission controller and using the username variable but it doesn't work.
def index
#submissions = Submission.all
#submissions.each do |submission|
username = User.find_by_id(submission.user_id).name.to_s
end
end
Model, add relation to user
class Submission
belongs_to :user
end
Controller, eager load users to avoid N+1 queries.
def index
#submissions = Submission.includes(:user).all
end
View, just project the user from each submission
<% #submissions.each do |submission| %>
<tr>
<td><%= submission.id %></td>
<td><%= submission.user.name.to_s %></td>
</tr>
<% end %>
#in controller
def index
#submissions = Submission.all
end
#in view
<% #submissions.each do |submission| %>
<tr>
<td><%= submission.id %></td>
<td><%= submission.user.name %></td>
</tr>
<% end %>
This code implies you have declared the following relations:
Submission belongs_to :user
User has_many :submissions (or has_one)
You can use eager loading (uses less queries to the DB) to improve the previous code:
#submissions = Submission.includes(:user).all
You can use an ActiveRecord association:
class Submission
belongs_to :user
# etc
end
Then in your view:
<td><%= submission.id %></td>
<td><%= submission.user.first_name</td> <!-- or whatever -->