Rails help looping through has one and belongs to association - ruby-on-rails

This is my kategori controller show action:
def show
#kategori = Kategori.find(params[:id])
#konkurrancer = #kategori.konkurrancer
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #kategori }
end
end
This is kategori view show file:
<% #konkurrancer.each do |vind| %>
<td><%= vind.name %></td>
<td>4 ud af 5</td>
<td><%= number_to_currency(vind.vaerdi, :unit => "DKK", :separator => ".", :delimiter => ".", :format => "%n %u", :precision => 0) %></td>
<td>2 min</td>
<td>Nyhedsbrev</td>
<td><%= vind.udtraekkes.strftime("%d %B") %></td>
</tr>
<% end %>
My kategori model:
class Kategori < ActiveRecord::Base
has_one :konkurrancer
end
My konkurrancer model:
class Konkurrancer < ActiveRecord::Base
belongs_to :kategori
end
I want show all of the konkurrancer that have an association to the kategori model
With my code I get the following error:
NoMethodError in Kategoris#show
Showing C:/Rails/konkurranceportalen/app/views/kategoris/show.html.erb where line #12 raised:
undefined method `each' for "#":Konkurrancer

The problem is that you are trying to loop over a has_one association. A has_one means exactly that - has one, so you can't call each on this because there is only one. You can do one of the following things to solve the problem in your code:
Use a has_many association:
class Kategori < ActiveRecord::Base
has_many :konkurrancers
end
Use a has_one association and modify your view:
<tr>
<td><%= #konkurrancer.name %></td>
<td>4 ud af 5</td>
<td><%= number_to_currency(#konkurrancer.vaerdi, :unit => "DKK", :separator => ".", :delimiter => ".", :format => "%n %u", :precision => 0) %></td>
<td>2 min</td>
<td>Nyhedsbrev</td>
<td><%= #konkurrancer.udtraekkes.strftime("%d %B") %></td>
</tr>
Which one you use really depends on your data model. If Kategori have many Konkurrancers then use the first example. If Kategori has one Konkurrancer, then use the second example. Both are valid.

Related

Access nested model attributes

I have following setup:
class EmpsController < ApplicationController
def new
#emp = Emp.new
#unit_options = Unit.all.collect{|unit| [unit.name, unit.id] }
end
def create
#emp = Emp.new(emp_params)
#emp.save!
redirect_to :action => :list
end
def destroy
#emp = Emp.find([:id])
#emp.destroy
redirect_to :action => :list
end
def list
#emps = Emp.all
end
def emp_params
params.require(:emp).permit(:name, :unit_id)
end
end
Model:
class Emp < ApplicationRecord
has_one :units
accepts_nested_attributes_for :units
end
Form:
<p> List of Employees: </p>
<table>
<% #emps.each do |u| %>
<tr>
<td><%= u.id %></td> <td><%= u.name %></td> <td><%= u.unit_id %></td> <td><%= link_to "Delete", u, :method => :delete %></td>
</tr>
<% end %>
</table>
All I want to do is to print (in table above) unit attribute called :name related with Emp printed Emp object.
Found various related solution but they do not apply to my case.
First, don't use :units as the association name, it "has one unit" no "units", Rails convention over configuration expects the association to be singular.
Then you should be able to do some_emp.unit.name.
Or you can use method delegation:
class Emp < ApplicationRecord
has_one :unit
delegate :name, to: :unit
end
And now you can do some_emp.name.

Sort order for ActiveRecord::Associations::CollectionProxy in table rails

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)

undefined method operators on legal Postgresql database

I'm beginner, so sorry if i ask for something trivial.
Two tables imed_patient and imed_operator are legal Postgresql tables with relation between them (many patients to one operator by r_opr_code field in imed_patient), described by definitions:
class ImedOperator < ActiveRecord::Base
self.table_name = "imed_operator"
self.primary_key = "code"
belongs_to :ImedPatient
end
class ImedPatient < ActiveRecord::Base
self.table_name = "imed_patient"
self.primary_key = "code"
has_one :ImedOperator, :foreign_key => "r_opr_code"
end
I want to view all patients with data (ex. name, surname) from imed_operator (details of patients), so I produced pacjenci_controller.rb
class PacjenciController < ApplicationController
def index
#patients = ImedPatient.all
#operator = #patients.operators
end
def show
#patient = ImedPatient.find(params[:id])
end
end
In web broweser I receive error :
NoMethodError in PacjenciController#index
undefined method `operators' for #<ImedPatient::ActiveRecord_Relation:0x007fbb269ffe00>
Extracted source (around line #5): #operator = #patient.operators
UPDATE:
my index.html.erb
<h1>Pacjenci w Optimed</h1>
<table>
<tr>
<th>Nazwisko</th>
<th>ImiÄ™</th>
<th>Pesel</th>
<th>Code_operator</th>
<th>Wizyty</th>
<th></th>
<th></th>
</tr>
<% #patients.each do |patient| %>
<tr>
<td><%= link_to #operator.surname, controller: "pacjenci", action: "show", id: patient.r_opr_code %></td>
<td><%= #operator.first_name %></td>
<td><%= #operator.pesel %></td>
<td><%= patient.r_opr_code %></td>
<td><%= link_to 'Wizyty', url_for(action: 'wizytypacjenta', controller: 'wizyty', id: patient.code) %></td>
</tr>
<% end %>
</table>
<br>
<p><%= link_to 'Start', url_for(action: 'index', controller: 'pacjenci') %></p>
<p><%= link_to 'Wstecz', url_for(:back) %></p>
And I stucked :(
ImedPatient has_one ImedOperator, so you need to change
#operator = #patient.operators
to
#operator = #patient.imed_operator
However, I'm not sure you are doing what you want to do. In the index action you are calling ImedPatient.all, so you will get all the records. That's why the variable should be called #patients, not #patient. Then, if you want to get all operators for all the patients, you should use
#operator = #patients.map(&:imed_operator)
If you made a mistake and you actually wanted the #operator in show action it should be:
#operator = #patient.imed_operator
Update: another problem is the has_one declaration. I think it should be:
has_one :imed_operator, :foreign_key => "r_opr_code"
Update 2:
After what you have written in comments it seems that you have confused the association and it should be the other way:
class ImedOperator < ActiveRecord::Base
has_one :imed_patient, foreign_key: 'r_opr_code'
end
class ImedPatient < ActiveRecord::Base
belongs_to :imed_operator , foreign_key: 'r_opr_code'
end
Have a look at: http://guides.rubyonrails.org/association_basics.html#choosing-between-belongs-to-and-has-one

Check whether a user owns a service

I have service and servicebooking models. I want to be able to check whether the current user owns a service and display the servicebookings that have been made for that users services.
I am trying to display this in a myservicebookings page.
This is the myservicebookings action in the servicebookings_controller, in the commented line Iam trying to check whether the current user is the owner of any of the servicebookings made or the owner of any of the services booked, I need to advise on how to go about this?
def myservicebookings
#servicebookings = current_user.services.servicebooking.find(params[:user_id])
#servicebookings = current_user.servicebookings.search(params[:search]).order(sort_column + " " + sort_direction).paginate(:per_page => 5, :page => params[:page])
end
This is the myservicebookings view, Iam trying to display both incoming/outgoing requests for services for the current user:
<h1>My Service bookings</h1>
<table>
<tr>
<th><%= sortable "date" %></th>
<th><%= sortable "time" %></th>
<th><%= sortable "service name" %></th>
</tr>
<% if #servicebookings.any? %>
<h4>Incoming requests:</h4>
<% #servicebookings.each do |servicebooking| %>
<tr>
<td><%= servicebooking.date %></td>
<td><%= servicebooking.time %></td>
<td><%= servicebooking.service_name %></td>
<td><%= link_to "View this booking", servicebooking_path(servicebooking) %></td>
</tr>
<% end %>
<h4>Outgoing requests:</h4>
<% #servicebookings.each do |servicebooking| %>
<tr>
<td><%= servicebooking.date %></td>
<td><%= servicebooking.time %></td>
<td><%= servicebooking.service_name %></td>
<td><%= link_to "View this booking", servicebooking_path(servicebooking) %></td>
</tr>
<% end %>
</table>
<%else%>
<%= "You have no incoming or outgoing service booking requests"%>
<%end%>
<%= will_paginate #servicebookings %>
<%= link_to "Homepage", :controller => "welcome", :action => "index" %>
Servicebooking model:
class Servicebooking < ActiveRecord::Base
attr_accessible :service_id, :date, :time, :user_id, :service_name, :accept_booking
belongs_to :user
belongs_to :service
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
Services model:
class Service < ActiveRecord::Base
attr_accessible :avatar, :avatar2, :avatar3, :avatar4, :name, :date_available, :time_available, :description, :price, :size, :company_name, :company_details
has_attached_file :avatar, :default_url => "/images/:style/missing.png"
has_attached_file :avatar2, :default_url => "/images/:style/missing.png"
has_attached_file :avatar3, :default_url => "/images/:style/missing.png"
has_attached_file :avatar4, :default_url => "/images/:style/missing.png"
belongs_to :user
belongs_to :event
has_many :comments, dependent: :destroy
has_many :servicebookings
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
Thanks guys, any help is appreciated.
You can do something like this in your controller. Assuming that there is a owner method on ServiceBooking and Service
def myservicebookings
#servicebookings = current_user.servicebookings.includes(:user).search(params[:search]).order(sort_column + " " + sort_direction).paginate(:per_page => 5, :page => params[:page])
owns_servicebooking = current_user.servicebookings.detect do |sb|
sb.user == current_user
end
owns_service = current_user.services.detect do |s|
s.user == current_user
end
#is_an_owner = owns_servicebooking and owns_service
end
detect returns an object if it matches the block and since it is ruby you can use it in a boolean expression to get what you want.
UPDATE: added controller method to the code example above. To use it in your view something like:
<% if #is_an_owner %>
<markup/>
<% end %>
I am pretty certain that this is not the best option in your case but I don't know enough about your stuff to suggest otherwise. It may be a start though. You may want to consider putting parts of this down to the model or into a helper method instead.

pass variables between two controllers

I have two controllers: tasks, tasksperson.
I have views/tasks/index.html.erb:
<table>
<% #tasks.group_by(&:name).each do |name, tasks| %>
<tr>
<td><%= name %></td>
<td><%= tasks.size %></td>
<td><%= tasks.select{ |task| task.done != true }.size %></td>
</tr>
<% end %>
</table>
I want to create a link in views/tasks/index.html to views/tasksperson/index.html.erb.I want also to send the name into 'index' in Tasksperson_controller.. I tried to do this by getting params[:name] but I think it's wrong
maybe, I need to do something like:
<td><%= link_to 'Show Tasks', tasksperson_path(name) %></td>
this is my tasksperson_controller:
class TaskspersonController < ApplicationController
def index
#tasks = Task.where(:name => params[:name]) respond_to do |format|
format.html # index.html.erb
format.json { render json: #tasks }
end
end
end
and views/tasksperson/index.html.erb:
<table>
<tr>
<th>Name</th>
<th>num of tasks</th>
<th>num tasks left</th>
<th>test</th>
</tr>
<% #tasks.each do |f| %>
<tr>
<td><%= f.name %></td>
<td><%= f.task %></td>
<td><%= f.done %></td>
</tr>
<% end %>
</table>
You need to add :name as a parameter to the rule that defines the route to TaskspersonController#index in routes.rb
so it would be something like this:
match 'tasksperson/index/:name' => 'tasksperson#index', as: :tasksperson_path
Based on your comment "...so Task have many taskpersons" I think you want a data model similar to below
class Task < ActiveRecord::Base
has_many :assigned_tasks
has_many :people, :through => :assigned_tasks
end
# maybe this is just the User class?
class Person < ActiveRecord::Base
has_many :assigned_tasks
has_many :tasks, :through => :assigned_tasks
end
# was TaskPerson
class AssignedTask < ActiveRecord::Base
belongs_to :task
belongs_to :person
end
See http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association for information about "The has_many :through Association"
task = Task.create(:title => "Go up the hill")
jack = Person.find(00000)
jill = Person.find(00000)
task.people << jack
task.people << jill
task.assigned_tasks.each do |join|
puts join.created_at
puts join.person.name
# 0 - jack
# 1 - jill
end
task.people.each do |person|
puts person.name
end
I am not exactly sure what you are trying to display in your views, it looks like you are grouping by a task name attribute in task/index, is that the Persons name?

Resources