pass variables between two controllers - ruby-on-rails

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?

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

Rails soft delete with has_many association

I got a small app where I got a simple user model, and I'm currently trying to add some soft delete functionality (yes, I know there are some gems for this). Works fine for users, however when I delete a user, the associated topic view collapses as it cannot find the deleted user anymore due to the default scope I guess.
Any idea how to get arround this?
class User < ActiveRecord::Base
has_many :topics
has_many :comments
default_scope { where(active: true) }
end
def index
#topics=Topic.all
end
class UsersController < ApplicationController
def index
if current_user and current_user.role == "admin"
#users=User.unscoped.all
else
#users=User.all
end
end
Part of the view (topic.user.name is where it stops working):
<% #topics.each do |topic| %>
<tr>
<td><%=link_to topic.title, topic %></td>
<td><%=h topic.description %></td>
<td><%= topic.user.name %></td>
<td><%=h topic.created_at.strftime('%Y %b %d %H:%M:%S') %></td>
<td><%=h topic.updated_at.strftime('%Y %b %d %H:%M:%S') %></td>
</tr>
<% end %>
This is why default_scope is evil. By now you've realized that having a default_scope can lead to a wild goose chase.
You can change user.rb to this:
class User < ActiveRecord::Base
has_many :topics
has_many :comments
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) } # can be used in future when you want to show a list of deleted user in a report or on admin panel.
end
then controller:
class UsersController < ApplicationController
def index
#users = User.scoped
#users = #users.active if current_user && current_user.role != 'admin'
end
end
view will have no problem of your topics#index now:
<% #topics.each do |topic| %>
<tr>
<td><%=link_to topic.title, topic %></td>
<td><%=h topic.description %></td>
<td><%= topic.user.name %></td>
<td><%=h topic.created_at.strftime('%Y %b %d %H:%M:%S') %></td>
<td><%=h topic.updated_at.strftime('%Y %b %d %H:%M:%S') %></td>
</tr>
<% end %>
Whenever you want to display active users just do: #users = User.active.
Use this, and leave the associations as it is.
<td><%= topic.user.try(:name) %></td>

Rails help looping through has one and belongs to association

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.

Resources