Rails display table data - ruby-on-rails

I have developed rails app with three classes.
class Location < ActiveRecord::Base
has_many :observations
end
class Observation < ActiveRecord::Base
belongs_to :location
has_one :rainfall
has_one :temperature
has_one :winddirection
has_one :windspeed
has_one :dewpoint
end
class Rainfall < ActiveRecord::Base
belongs_to :observation
end
Railfall is related to Observation through an observation_id and Observation is related to Location through a location_id.
If i go to console and type something like:
Location.all.first.observations.first.rainfall.value
it returns me the data in value column of rainfall
However when i want to combine all the info in rails in a table and in my view/location/index.html.erb i put:
<tbody>
<% #locations.each do |location| %>
<tr>
<td><%= location.name %></td>
<% unless #observations = nil %>
<% location.observations.each do |obs| %>
<td><%= obs.name %></td>
<% unless #rainfalls = nil %>
<td><%= obs.rainfalls.value %></td>
<% end %>
<% end %>
I get an error:
undefined method `rainfalls' for Observation:0x00000004219068>
I have spent the last 5 hours trying just about everything i can and am getting a tad frustrated....any ideas?
Note i have a locations controller but observation and rainfall were generated as models, so do not. Am thinking i need to add something to my location controller, just can't work out what, and I am unsure why it returns the correct data in console, just no in app.

Observation.has_one :rainfall, so it should be:
<%= obs.rainfall.value %>

You have one to one relationship, not has_many. Replace
<%= obs.rainfalls.value %>
by
<%= obs.rainfall.value %>

Related

Eager Loading Nested Association

I have the following models:
class Session < ActiveRecord::Base
belongs_to :game
has_many :session_players
has_many :players, through: :session_players
end
class SessionPlayer < ActiveRecord::Base
belongs_to :player
belongs_to :session
end
class Player < ActiveRecord::Base
has_many :session_players
has_many :sessions, through: :session_player
end
In the erb file I am trying to loop over all sessions, displaying some info about the session and displaying nested data about each player for that session.
The relevant code in the erb file is:
<% #sessions.each do |session| %>
<tr>
<td><%= session.name %></td>
<td>
<table>
<% session.session_players.each do |session_player| %>
<!-- problem line below -->
<tr><td><%= session_player.player.name %> (<%= session_player.placing %>)</td></tr>
<% end %>
</table>
</td>
</tr>
<% end %>
The problem is that I cannot pull data off of both the player and the session_player object due to a null exception when getting the name value off of the session_player.player.name call. The call to the session_player.placing succeeds.
I believe this to be a lazy loading issue as I can retrieve the value of session_player.player.name while debugging the code, just not when running it. I tried eager loading the data by trying various includes combinations in the controller but it did not make a difference:
#sessions = Session.includes(:session_players => :player).all
How about this:
#sessions = Session.joins(:session_players)
Or to avoid N+1
#sessions = Session.includes(:session_players)
You can use try to define when there is no relation
<% session.session_players.each do |session_player| %>
<!-- problem line below -->
<tr><td><%= session_player.try(:player).try(:name) %> (<%= session_player.placing %>)</td></tr>
<% end %>
The code was correct, but the data I was populating it with was not. One of the values was null later in the list of data. This was not being caught until the data was being accessed during template rendering. Eager loading had no effect on when the data when the exception occurred.

Rails printing the value of a database column

I'm new to rails and I have been experimenting. I have to tables companies and contacts and i have set up the associations and relationship. what I would like to do is this.
Currently, in the contacts table it brings back a number for the value of the company name. What I would like instead is the the value of the company name instead of the number. I have tried changing it from the company_id to company_name - but I then get an error about no method being found. Can anyone help on how I do this.
You can delegate to the company
class Contact < ActiveRecord::Base
delegate :name, to: :company, prefix: true
end
<%= #contact.company_name %>
I assume a contact will always belong to a company, if not add, allow_nil: true
If you're looping through them like this:
<% #contacts.each do |contact| %>
<tr>
<td><%= #contact.company_name %></td>
</tr>
<% end %>
I doubt you've defined #contact as you're looping through #contacts calling them contact you want
<% #contacts.each do |contact| %>
<tr>
<td><%= contact.company_name %></td>
</tr>
<% end %>
I.e. without the # - you're using a local variable not an instance variable.

Issue ordering array in the view

I'm trying to order a column inside array but is not ordering is showing values without ordering by lastname ASC.
Here is my table:
|products|
|id| |money| |client_id|
1 1000 1
2 2000 4
3 2000 7
4 2000 5
5 2000 6
6 2000 3
7 2000 2
|customers|
|id| |name| |lastname1| |lastname2|
1 Lionel Messi Bueno
2 Cristiano Ronaldo Tiger
3 Cecs Fabregas Midtlon
4 Andres Iniesta Blanco
5 Neymar Dos Santos Junior
Here is my controller
class ProductController < ApplicationController
def index
#products= Product.all
end
end
Here is the model
class Client < ActiveRecord::Base
has_many :products
def str_name
return lastname1.to_s+" "+lastname2.to_s+" "+name.to_s
end
end
class Product < ActiveRecord::Base
belongs_to :client
end
Here is my view
<table>
<tr>
<td>Money</td>
<td>Client</td>
</tr>
<% #products.each do |p| %>
<tr>
<td><%= p.money %></td>
<td><%= p.str_name %></td>
<% end %>
</tr>
</table>
I tried but is not ordering by lastname1 asc:
<% #products.each do |p| %>
<tr>
<td><%= p.money %></td>
<td><% #a= p.client(:order=>"lastname1 ASC")%> <%= #a.str_name %></td>
<% end %>
The log is:
SELECT * FROM `clients` WHERE (`clients`.`id` = 1)
SELECT * FROM `clients` WHERE (`clients`.`id` = 2)
SELECT * FROM `clients` WHERE (`clients`.`id` = 3)
SELECT * FROM `clients` WHERE (`clients`.`id` = 4)
And should be like this:
SELECT * FROM `clients` order by last_name1 ASC
Please somebody can help me?
<% #a= p.client(:order=>"lastname1 ASC")%> <%= #a.str_name %></td>
The line above does technically nothing. When you are already in the loop and you ask for the client of the current product, how many is it going to return? Only one, right ? Right, if you have a belongs_to on the other side (which I hope you do, this answer relies on it). So you're actually "sorting" a set of one element every iteration. And that's why your Select is ignoring the "order by". What you should be doing though, is to get a list of all the products ordered by their respective clients' "lastname1". This should not be done in a view like you're trying to do, but in your controller. In your controller:
#In Rails 4
#products = Product.joins(:client).order('clients.lastname1 ASC')
#Other version (be careful where to use plurals and where not to)
#products = Product.find(:all, :joins => :client, :order => 'clients.lastname1 ASC')
And in your view:
<% #products.each do |p| %>
<tr>
<td><%= p.money %></td>
<td><%= p.client.str_name %></td>
</tr>
<% end %>
<% #products.each do |p| %>
<tr>
<td><%= p.money %></td>
<td><% #a= p.client(:order=>"lastname1 ASC")%> <%= #a.str_name %></td>
<% end %>
Not sure if this answers your question, but in the second td, the ERB tag isn't printing out anything to the page. Check your syntax.
If you're actually trying to set #a equal to something like that, it's best done in the controller.
That was just something I noticed. I'll continue to look at your code to see if I can find why you're not getting the result you desire.
In your code, it looks like each product only has one client, however I can't be sure since you did not post code for your Product model. If that is the case, then p.client will only ever return one client, and there is no reason to sort the results; ActiveRecord may be smart enough to skip that step. This could also explain the queries in your log.
If you want a many-to-many relationship between clients and products, you should create a join table.
rails generate model ClientProduct client_id:integer product_id:integer
Your resulting relationships would be
Client:
class Client < ActiveRecord::Base
has_many :client_products
has_many :products, :through => :client_products
...
end
Product:
class Product < ActiveRecord::Base
has_many :client_products
has_many :clients, :through => :client_products
...
end
ClientProduct:
class ClientProduct < ActiveRecord::Base
belongs_to :client
belongs_to :product
...
end

Create multiple records related to existing model

I'm a rails noob trying to develop a simple exercise log app, and I'm up against my limits. 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
My problem is that I'm not sure about my approach up to this stage. It does work so I have attempted to enable the user to log their workout by using a form like the following but I'm (not surprisingly) not getting the right info back from it and I'm not sure where to go with it...
<%= 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>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag "Log it" %>
<% end %>
If anybody has any thoughts/guidance/solutions I'd appreciate it

Identifying Model Instance by Two Relations

I'm trying to pick out an instance of a model ("Package") by its relation to two other models to which it belongs ("Cut" and "Animal"). While there are, say many packages with :cut_id 3 and many with :animal_id 4, there should only be one with both, and I want to pick that one out and display its contents in a table.
I've tried the following DIY mess, and it's not really working. (cutfind is a method I created that I know works for calling out all of the cuts associated with the given animal.)
<% #animal.cutfind.each do |cut| %>
<tr>
<td><%= cut.name %></td>
<td><%= number_to_currency(cut.price) %></td>
<td><%= cut.package_weight %> lb</td>
<% #a = Package.where(:animal_id => #animal.id) %>
<% #pset = #a.where(:cut_id => cut.id) %>
<% #pset.each do |p| %>
<td><%= p.original %></td>
<td><%= p.left %></td>
<% end %>
</tr>
<%end%>
Any idea how to do this [better]? Thanks.
Update: I tried this other DIY mess and am getting the same problem (the cells aren't even being created, which leads me to believe that #pset is empty).
This is in my animal model:
def packagefind
Package.where(:animal_id => self.id)
end
And then I changed the above like so:
<td><%= cut.package_weight %> lb</td>
<% #pset = #animal.packagefind.where(:cut_id => cut.id) %>
<% #pset.each do |p| %>
<td><%= p.original %></td>
<td><%= p.left %></td>
<% end %>
Rails will automatically generate methods to help you find the associated records if you define the following relations:
class Animal
has_many :cuts
has_many :packages, :through => :cuts
end
class Cut
belongs_to :animal
belongs_to :package
end
class Package
has_many :cuts
has_many :animals, :through => :cuts
end
In your controller, the following line will eager load all the records you will need in your view:
#animal = Animal.includes(:cuts => :package)
Your view can then be shortened to:
<% #animal.cuts.each do |cut| %>
<tr>
<td><%= cut.name %></td>
<td><%= number_to_currency(cut.price) %></td>
<td><%= cut.package_weight %> lb</td>
<td><%= cut.package.original %></td>
<td><%= cut.package.left %></td>
</tr>
<%end%>
As I'm not able to comment on your post, I take a guess:
You have the folllowing architecture:
Cut -> Package <- Animal
In this, "->" and "<-" are one-to-many relationships so that
class Package < ActiveRecord::Base
has_many :cuts
has_many :animals
end
So, you want "the" package, that has Cut with id 3 and Animal id 4.
Did you try:
x = Product.select { |product| product.cuts.include?(Cut.find(3)) }.select{ |product| product.animals.include?(Animal.find(4)) }
?
EDIT: I first suggested to you use
Product.find_by_product_id_and_animal_id()
which didn't work but showed the OP the way to do it

Resources