Rails 3: Join results in a view - sql

Again I'm faced with something that should not on the face of it be this difficult but has been driving me mad for an hour or so. I have multiple models which I want to pull into one 'index' view. I assume it's a join but I can't seem to find a way to do it.
What I have in my index view:
<% #tips.each do |tip| %>
<tr>
<td><%= tip.user_id %></td>
<td><%= tip.city_id # here I want to draw on the cities table to show city.name
%></td>
<td><%= tip.type_id # here I want to draw on the type table to show type.name
%></td>
<td><%= tip.place_id # here I want to draw on the place table to show place.name
%></td>
<td><%= tip.tip_desc %></td>
<td><%= link_to 'Show', tip %></td>
<td><%= link_to 'Edit', edit_tip_path(tip) %></td>
<td><%= link_to 'Destroy', tip, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
Here are the models:
class Tip < ActiveRecord::Base
belongs_to :user
belongs_to :city
belongs_to :place
end
class Place < ActiveRecord::Base
belongs_to :city
has_and_belongs_to_many :collections
has_many :tips
end
class City < ActiveRecord::Base
has_many :places
has_many :tips
end
Any help will be really appreciated!
Thanks in advance,
James

Suggestions from other guys should work. I'm not sure, but it seems like you don't have objects within specified IDs in your database. That's all :)
Example:
#tips.each do |tip|
tip.city_id # 1
City.find( tip.city_id ) # nil
end

Related

Associations in Rails 3

I have an app which allows users to add recipes and then select their favourite recipes to view in their member area, I can select a favourite and i am getting the user_id, recipe_id and giving it a favourite_id.
What I would like to do is output the actual recipe to my view (as a favourite), like dish name, country_of_origin etc. I can do this with an actual recipe but not the favourite.Do i need to use has_many_through for this?
My models look like this
User
has_many :recipes
has_many :favourites
recipe
belongs_to :user
has_many :ingredients
has_many :preperations
has_many :favourites
favourites
belongs_to :user
belongs_to :recipe
attr_accessible :user_id, :recipe_id
My controller
#favourites = current_user.favourites
my link_to post
<%= link_to "Add to favorites", {:controller => 'favourites', :action => 'create', :recipe_id => r.id}, {:method => :post } %>
i can list the current users recipes, this is my contoller for this
#recipes = current_user.recipes if current_user.recipes
and then output them to the view like so
<% #recipes.each do |r| %>
<tr>
<td><%= r.dish_name %></td>
<td><%= r.country_of_origin %></td>
<td><%= r.difficulty %></td>
<td><%= r.preperation_time %></td>
<td><%= ingredient_names(r.ingredients) %></td>
<td><%= preperation_steps(r.preperations) %></td>
<td><%= image_tag r.avatar.url(:thumb)%></td>
<tr>
So if i do this in the view
<li><%= #favourites %></li>
I get this outputted
<Favourite id: 16, user_id: 8, recipe_id: 21, created_at: "2012-11-07 20:24:39", updated_at: "2012-11-07 20:24:39">]
If i try
<%= #favourites.dish_name %>
then i get the error undefined method dish_name
How do i get the params of the recipe model to show in the view. I do apologise just cant work it out, which should be really easy i guess?
Any help appreciated
You get undefined dish_name because your Favourite model does not have such attribute.
#favourites = current_user.favourites returns an array of Favourite objects.
In your view you would do something like
<% #favourites.each do |f| %>
<%= f.recipe %>
<% end %>
That will display all the recipes your current_user favorites. You could narrow it down to display a specific recipe or what not.
The favorites is just holding the relationship.
You can access the recipe by
#favourites.recipe
which will then be a recipe object and contain your attributes like dish_name etc.
#favourites is an array, yes? Then you must loop through #favourites and work with each element individually as so:
<% #favourites.each do |favorite| %>
<%= favorite.recipe.dish_name %>
<% end %>

Country name not saving to table or showing in view rails 3

I have a simple app where you can upload recipes
I have just integrated the gem terrarum to give me all the countries of the world within my country model. I have a relationship where a recipe has_one country and a country belongs to recipe. I am using nested forms from ryan bates and have had no problem getting information to show from my ingredients model and preparation model. But i cannot get the country name to save in the table or show in the view (though this is caused by not saving to model)
Code is as follows
Form
<%= f.label :country_id, "Country Of Origin" %>
<%= f.collection_select(:country_id, Country.all, :id, :name, :prompt => 'Please select country') %>
View
<% #recipes.each do |r| %>
<tr>
<td><%= r.dish_name %></td>
<td><%= r.country.name %></td>
<td><%= r.difficulty %></td>
<td><%= r.preperation_time %></td>
<td><%= ingredient_names(r.ingredients) %></td>
<td><%= preperation_steps(r.preperations) %></td>
<td><%= image_tag r.avatar.url(:thumb)%></td>
</tr>
Helper
def preperation_steps(preperations)
if preperations
preperation_array = preperations.map {|pre| pre.prep_steps}
preperation_array.join("\n")
end
end
def country_name(country)
if country
country_array = country.map {|c| c.country_name}
country_array.join("\n")
end
end
end
I have included my preparation helper as this works, so surely my country_name helper mirrors this? or do i not need to put a helper in for this?
recipe controller
def new
#recipes = current_user.recipes if current_user.recipes #show recipes if the user has any recipes
#favourites = current_user.favourites
end
recipe model
belongs_to :user
belongs_to :country
has_many :ingredients
has_many :preperations
has_many :favourites
attr_accessible :dish_name, :difficulty, :preperation_time, :ingredients_attributes, :preperations_attributes, :country_id, :avatar:preperations_attributes, :country_id, :avatar
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
accepts_nested_attributes_for :ingredients, :preperations
scope :top_countries, order("country_of_origin DESC")
if anyone can help it would be much appreciated
Thanks
In this code I see two mistakes:
Recipe should belong_to :country. Don't use has_one here. The foreign key country_id should be in the recipes table.
#recipe.build_country is not necessary. You already have a list of countries. You should only use build_country if you are planning to add a new country to the list of countries, which you are not in this case.
Also, you don't need fields_for. You can just do:
<%= f.label :country_id, "Country Of Origin" %>
<%= f.collection_select(:country_id, Country.all, :id, :name, :prompt => 'Please select country') %>

Simple associations with a legacy database in Rails 3?

I am working with a legacy database and am also reading through the Rails guides on associations.
I have two models. A diary model and an animal model.
diary.rb
class Diary < ActiveRecord::Base
establish_connection :premvet
attr_accessible :DiaryNo ,:DiaryName, :DiaryDate, :SlotHour, :TotalSlots, :BlockSlots, :BlockBooked, :FreeSlot, :BookedSlot
self.table_name = 'diary'
self.primary_key = 'DiaryNo'
has_many :animals, :foreign_key => 'DiaryQueue'
end
animal.rb
class Animal < ActiveRecord::Base
establish_connection :premvet
self.table_name = 'animal'
self.primary_key = 'PVID'
attr_accessible :AddedBy, :Age, :AnimalBFAmount, :AnimalBalance, :AnimalName, :Archive, :BillType, :Breed, :ChronicStatus, :Class, :Classification, :ClientKey, :Colour, :Date1, :DateOfBirth, :DateofBirth, :Dead, :DiaryQueue, :DiscField, :DrugsAtCost, :DrugsNoVAT, :ESDAmount, :ESDType, :FNote, :FirstRegisteredDate, :Height, :IDNumber, :Insured, :InsuredWith, :IsClient, :IsClientDate, :IsMaster, :LastBilledAmount, :LastBilledDate, :LastConsDate, :LastContributionDate, :LastPaidDate, :LastWeightDate, :Locked, :LoyaltyMultiplier, :LoyaltyPoints, :MR_Flag_0, :MR_Flag_1, :MR_Flag_10, :MR_Flag_11, :MR_Flag_12, :MR_Flag_13, :MR_Flag_14, :MR_Flag_15, :MR_Flag_2, :MR_Flag_3, :MR_Flag_4, :MR_Flag_5, :MR_Flag_6, :MR_Flag_7, :MR_Flag_7, :MR_Flag_8, :MR_Flag_9, :Mileage, :Neutered, :NextApptDate, :ORT, :OldSex, :Opt_Flag_0, :Opt_Flag_1, :Opt_Flag_2, :Opt_Flag_3, :Opt_Flag_4, :Opt_Flag_5, :Opt_Flag_6, :Opt_Flag_7, :PVID, :PreferredContact, :PreferredUser, :Ref1, :RefPrac, :ReferredBy, :SSDType, :SeenInPeriod, :SendBill, :Sex, :SiteAnimal, :Species, :Status, :SurcAmount, :SurcType, :SurgeryNumber, :TBU, :TOSAmount, :TOSDrugs, :TOSFees, :TOSType, :Weight
belongs_to :client, :foreign_key => 'ClientKey'
belongs_to :diary, :foreign_key => 'DiaryNo'
end
animals index view
<% #animals_todaysappointments.each do |animal| %>
<tr>
<td><%= animal.id %></td>
<td><%= animal.AnimalName %></td>
<td><%= link_to animal.client.Surname, animal.client %></td>
<td><%= animal.Species %></td>
<td><%= animal.Breed %></td>
<td><%= animal.NextApptDate.strftime("%d %b. %Y - %H:%M") %></td>
<td><%= animal.DiaryQueue %>
<td><%= animal.diary.DiaryName %></td>
<td><%= link_to 'Show', animal %></td>
</tr>
<% end %>
As you can see it's showing the DiaryQueue from the animal table using:
<td><%= animal.DiaryQueue %>
and I am trying to show the DiaryName from the diary table with:
<td><%= animal.diary.DiaryName %></td>
This fails with an exception error:
undefined method `DiaryName' for nil:NilClass
The #animals_todaysappointments method looks like this:
def appointments
#animals_todaysappointments = Animal.where('DATE(NextApptDate) = ?', Date.today).page(params[:page]).per_page(15).order('NextApptDate ASC')
respond_to do |format|
format.html # index.html.erb
end
end
If I add:
delegate :DiaryName, :to => :diary
to the animal model then I get the following error:
Animal#DiaryName delegated to diary.DiaryName, but diary is nil: #
Each animal record has a DiaryQueue value between 0 and 10 and the diary table has a number of rows, an example row is:
DiaryNo DiaryName DiaryDate SlotHour TotalSlots BlockBooked FreeSlot BookedSlot
--------------------------------------------------------------------------------------
1 Morning 2012-07-16 9 18 0 0 18
There are rows with the same DiaryNo, but they also have the same DiaryName. It's only the DiaryDate, SlotHour, TotalSlots, BlockBooked, FreeSlot and BookedSlot that alter in those rows.
To try and prevent the error I added the following to the view:
<% unless animal.DiaryName.nil? %>
<td><%= animal.DiaryName %></td>
<% else %>
<td><%= animal.DiaryQueue %>
<% end %>
but I get an exception:
Animal#DiaryName delegated to diary.DiaryName, but diary is nil: #
What am I doing wrong?
Given your answers above, you might need to change the belongs_to method in Animal to the following:
belongs_to :diary, :foreign_key => "DiaryQueue", :primary_key => "DiaryNo"
In your current implementation your models are going to try to match Animal#DiaryNo against Diary#DiaryNo, when what you've said you wanted is to match Animal#DiaryQueue against Diary#DiaryNo.

What am I doing wrong with Rails has_many and belongs_to association?

I'm creating an app to log when files are moved to an archive drive, where they came from and were moved to and what user moved them.
This is my Archive model:
class Archive < ActiveRecord::Base
attr_accessible :archive_date, :start_dir, :end_dir, :user_id
#added by chris
belongs_to :user
end
This is my User model:
class User < ActiveRecord::Base
# new columns need to be added here to be writable through mass assignment
attr_accessible :username, :email, :password, :password_confirmation, :user_id
attr_accessor :password
before_save :prepare_password
before_save :assign_user_id
#added by chris
has_many :archives
def assign_user_id
self.user_id = User.maximum('user_id') + 1
end
end
This is my view:
<table id="archive_table">
<tr>
<th>Archive Date</th>
<th>Source Directory</th>
<th>Archive Directory</th>
<th>Archived By ID</th>
<th>Archived By Name</th>
</tr>
<% for archive in #archives %>
<tr>
<td><%= archive.archive_date %></td>
<td><%= archive.start_dir %></td>
<td><%= archive.end_dir %></td>
<td><%= archive.user_id %></td>
<td><%= archive.username %></td>
<td><%= link_to "Show", archive %></td>
<td><%= link_to "Edit", edit_archive_path(archive) %></td>
<td><%= link_to "Destroy", archive, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<p><%= link_to "New Archive", new_archive_path %></p>
When I start up my local rails server via rails s Try to load the page. This is what I get:
NoMethodError in Archives#index
Showing c:/appname/app/views/archives/index.html.erb where line #21 raised:
undefined method `username' for #<Archive:0x203d750>
Extracted source (around line #21):
18: <td><%= archive.start_dir %></td>
19: <td><%= archive.end_dir %></td>
20: <td><%= archive.user_id %></td>
21: <td><%= archive.username %></td>
22: <td><%= link_to "Show", archive %></td>
23: <td><%= link_to "Edit", edit_archive_path(archive) %></td>
24: <td><%= link_to "Destroy", archive, :confirm => 'Are you sure?', :method => :delete %></td>
Rails.root: c:
Application Trace | Framework Trace | Full Trace
app/views/archives/index.html.erb:21:in `block in _app_views_archives_index_html_erb__238412483_16592988'
app/views/archives/index.html.erb:15:in `each'
app/views/archives/index.html.erb:15:in `_app_views_archives_index_html_erb__238412483_16592988'
Assuming the archive record is correctly saved with the users User_ID how do i get my view to display the name of the user via the has_many belongs_to association?
Thank You for looking at my question.
Archives have users, users have usernames--I think you're just up one level to "high"; use:
<%= archive.user.username %>

Rails calling a controller from another model's view

I have a post model and an upvote model.
upvote.rb
class Upvote < ActiveRecord::Base
has_one :user
belongs_to :post
end
# == Schema Information
#
# Table name: upvotes
#
# id :integer not null, primary key
# user_id :integer
# post_id :integer
# comment :text
# created_at :datetime
# updated_at :datetime
#
Now within posts/index I want to add an upvote for the current user and the post.
Some research pointed me to write a helper
posts_helper.rb
module PostsHelper
def upvote_post(post)
#upvote = Upvote.new
#upvote.user_id = current_user.id
#upvote.post_id = post.id
if #upvote.save
flash.now[:notice] = 'Upvote was successfully created.'
end
end
end
Inside my view I want to call the helper only on clicking a link but can't seem to get link_to working properly.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats" upvote_post(post) %></td>
<td><%= post.name %></td>
...
I get the error syntax error, unexpected tIDENTIFIER, expecting ')' and can't seem to find any good alternatives.
What am I missing here?
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...
Closing open question.
It was a comma.
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...