display "name" insted of "_id" in index view - ruby-on-rails

I've got "demand", "shift" and "parent" (this is going to be a baby sitter thingy).
Now the models look like this:
class Demand < ActiveRecord::Base
belongs_to :parent
belongs_to :shift
end
&
class Parent < ActiveRecord::Base
has_many :demands, :dependent => :destroy
has_many :shifts, :through => :demands
accepts_nested_attributes_for :demands, allow_destroy: true
# Returns fullname of parent
def fullname
"#{firstname} #{name}"
end
end
&
class Shift < ActiveRecord::Base
has_many :supps, :dependent => :destroy
has_many :nanns, :through => :supps
has_many :demands, :dependent => :destroy
has_many :parents, :through => :demands
end
If I now want to display a shift's description (a param of the shift table) instead of its _id, I get the following error:
undefined method `description' for nil:NilClass
Here is some code from the corresponding demands index view:
<td><%= demand.parent.name %></td>
<td><%= demand.demand %></td>
<td><%= demand.shift.description %></td> <----THIS LINE PRODUCES THE ERROR
<td><%= link_to 'Show', demand %></td>
<td><%= link_to 'Edit', edit_demand_path(demand) %></td>
<td><%= link_to 'Destroy', demand, method: :delete, data: { confirm: 'Are you sure?' } %></td>
I think that I gave the models the correct has_many and belongs_to associations so I don't really find the mistake here. Thanks in advance for any help!

You have a demand that has no associated shift. If you want to identify which one in your table, replace...
<td><%= demand.shift.description %></td>
with
<td><%= demand.shift ? demand.shift.description : 'missing shift!' %></td>
The lines with missing shifts will now tell you that shift is missing.

Related

How do I get the table column data from one model into the view of another?

I want the customer name to appear in the customer name column on one of my model view pages, but I can't seem to figure out how to do this.
Here are my associations:
Customer Model is -
class Customer < ActiveRecord::Base
has_many :appointments, :dependent => :destroy, :as => :customer
has_many :birds, :dependent => :destroy, :as => :customer
end
Bird Model is -
class Bird < ActiveRecord::Base
belongs_to :customer
has_one :appointment
end
I've also added this to the Bird model index view -
<tbody>
<% #birds.each do |bird| %>
<tr data-link="<%= bird_path(bird) %>">
<td><%= bird.customer_id %></td>
<td><%= bird.name %></td>
<td><%= bird.breed %></td>
<td><%= bird.color %></td>
<td><%= bird.age %></td>
</tr>
<% end %>
The customer parameter I'd like to pass into the customer name column on the birds index view page is customer.name, or :name. If I try that, I get an undefined methods error on my /birds page.
Thanks!
I would expect that this should work:
<%= bird.customer.name %>
Or - if you have birds without an customer - you might want avoid exceptions like this:
<%= bird.customer.try(:name) %>
Or - less error prone - add the following to your bird model:
delegate :name, to: :customer, allow_nil: true, prefix: true
And use it in your views like this:
<%= bird.customer_name %>
You need to use in your view like this :
<%= bird.customer.name %>
In your controller, for the bird index page:
when you query for Bird.all, do Bird.all.includes(:customer)
then you will have access to <%= bird.customer.name %> in the view

Ruby - access parent property from child - one to many relation

class PriceList < ActiveRecord::Base
has_many :prices, :dependent => :destroy
end
and Price:
class Price < ActiveRecord::Base
belongs_to :price_list
belongs_to :material
belongs_to :unit
end
Now in price_list index I want to show Price list name instead of id:
<tbody>
<% #prices.each do |price| %>
<tr>
<td><%= price.price_list.price_list_short_name %></td>
<td><%= price.materials_id %></td>
<td><%= price.units_id %></td>
<td><%= link_to 'Show', price %></td>
<td><%= link_to 'Edit', edit_price_path(price) %></td>
<td><%= link_to 'Destroy', price, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
What I am doing wrong that price.price_list.price_list_short_name does not work?
At least one of your Price records doesn't have its price_list associated. The solution depends on your intentions. If you want to force all prices to have price_list, you can add validation:
class Price < ActiveRecord::Base
validates :price_list, presence: true
# ...
end
If you want to allow price_list-less prices, you could make use of try method, which will fix the error in view:
price.price_list.try(:price_list_short_name)
BTW, naming your column price_list_short_name in price_lists table is a bit redundant.
I was missing proper references.
Adding to migration file:
class AddReferencesToPrices < ActiveRecord::Migration
def change
remove_column :prices, :price_list_id
remove_column :prices, :materials_id
remove_column :prices, :units_id
add_reference :prices, :price_list, :index => true
add_reference :prices, :material, :index => true
add_reference :prices, :unit, :index => true
end
end
solved problem.

Recursive association behaves differently in index/show/edit actions

I'm trying to use recursive association in Ruby on Rails and I'm not getting the expected output :) I want to have match with two players (winner and loser) and I thought about recursive association.
I used scaffolds to get the basics done:
rails g scaffold Player firstname:string lastname:string
rails g scaffold Match date:date result:integer winner:references loser:references
And then modified Match model:
class Match < ActiveRecord::Base
has_one :winner, class_name: 'Player', foreign_key: 'id'
has_one :loser, class_name: 'Player', foreign_key: 'id'
end
However if I add manually some players and go to match#index both winner and loser are the same (even if I set them to be different).
Part of view is like this:
<tbody>
<% #matches.each do |match| %>
<tr>
<td><%= match.date %></td>
<td><%= match.result %></td>
<td><%= match.winner %></td>
<td><%= match.loser %></td>
<td><%= link_to 'Show', match %></td>
<td><%= link_to 'Edit', edit_match_path(match) %></td>
<td><%= link_to 'Destroy', match, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
When I edit Match, then I clearly see that there are different IDs of players, but in show or index both players are the same.
What am I doing wrong?
Thank you :)
You are using an "has_one" association, which is actually setting the database link on the other class/table (here, Player). This is not what you want: you want to have two foreign keys (winner_id and loser_id) on the Match table.
This can be done using the much more common "belongs_to" association:
class Match < ActiveRecord::Base
belongs_to :winner, class_name: "Player"
belongs_to :loser, class_name: "Player"
end

Ruby on Rails Accessing attributes of record found using .last

In my asset index view, when it loops through each Asset, I want to show the most recent scene name. I am using .last to pull out the most recent record. When I .inspect what is returned, I can see the values. The problem is, when I try to access one of the attributes of what is returned I get an undefined method.
So for instance if I do this:
<%= (asset.scene_assignments.where(asset_id: asset).order("created_at").last).scene_id %>
I get:
NoMethodError in Assets#index undefined method `scene_id' for SceneAssignment:0x4bc2c28
But if I call #inspect instead of #name, I can see what is contained inside. So if I do this:
<%= (asset.scene_assignments.where(asset_id: asset).order("created_at").last).inspect %>
It prints this:
SceneAssignment id: 4, scene_id: 3, asset_id: 1, arrival_time: nil, created_at: "2014-10-16 01:43:50", updated_at: "2014-10-16 01:43:50", location_id: 1, asset_role_id: 1
Why can't I access one of the attributes from what is returned?
In my asset index view, I have this:
<% #assets.each do |asset| %>
<tr>
<td><%= asset.name %></td>
<td>
<%= (asset.scene_assignments.where(asset_id: asset).order("created_at").last).inspect %>
</td>
<td><%= link_to 'Show', asset %></td>
<td><%= link_to 'Edit', edit_asset_path(asset) %></td>
<td><%= link_to 'Destroy', asset, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
My relationship between an asset and scene is set up like this:
class SceneAssignment < ActiveRecord::Base
belongs_to :scene
belongs_to :asset
belongs_to :location
belongs_to :asset_role
belongs_to :incident
accepts_nested_attributes_for :asset
end
class Scene < ActiveRecord::Base
has_many :scene_assignments
has_many :assets, :through => :scene_assignments
belongs_to :incident
belongs_to :scene_type
accepts_nested_attributes_for :scene_assignments, :allow_destroy => true
end
class Asset < ActiveRecord::Base
has_many :scene_assignments
has_many :scenes, :through => :scene_assignments
end
I believe it is .scene_id, not .last that is causing your error. The result of `.where(…) is a collection of records, not a single record.
To fix that, you could say asset.scene_assignments.where(asset_id: asset).order("created_at").last).first.scene_id though that makes some fairly messy code just a little bit worse. :)

Accessing Attributes in a Many-to-Many

I have a rails app and I'd like to be able to do something like
task.labels.first.label_name to get the label name of a task. However, I get an undefined method label_name. I did a t = Task.first; t.labels.first.label_name in the console, and that worked so I'm not sure what's going on. Here's the models then the locations of the error:
class Categorization < ActiveRecord::Base
belongs_to :label
belongs_to :task
end
class Label < ActiveRecord::Base
attr_accessible :label_name
has_many :categorizations
has_many :tasks, :through => :categorizations
end
class Task < ActiveRecord::Base
attr_accessible :task
has_many :categorizations
has_many :labels, :through => :categorizations
end
The error is in the index
<% for task in #tasks %>
<tr>
<td><%= task.task %></td>
<td><%= task.labels.first.label_name %></td>
<td><%= link_to "Show", task %></td>
<td><%= link_to "Edit", edit_task_path(task) %></td>
<td><%= link_to "Destroy", task, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
My guess would be that one of the tasks in #tasks does not have any labels so when you call task.labels.first it returns nil and then you try to call label_name for nil which of course does not work.
The easiest solution would be to do a check like this:
<td><%= task.labels.first.label_name unless task.labels.first.nil? %></td>
Now that does not look so good in the view so you might want to place that check in your Task model instead, perhaps like this:
class Task < ActiveRecord::Base
attr_accessible :task
has_many :categorizations
has_many :labels, :through => :categorizations
def label_name
self.labels.first.label_name unless self.labels.first.nil?
end
end
And in the view:
<td><%= task.label_name %></td>
And another thing, just in case you would like to view all the associated labels, you could do something like this:
task.labels.map(&:label_name).join(", ")

Resources