Simple associations with a legacy database in Rails 3? - ruby-on-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.
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') %>
Rails 3: Join results in a view
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
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 %>
Using :joins in Ruby on Rails 3
Greetings I have 3 db tables: Types id name Sources id name type_id Operations id source_id comment ... and models for each: class Type < ActiveRecord::Base has_many :sources, :dependent => :destroy end class Source < ActiveRecord::Base belongs_to :type has_many :operations, :dependent => :destroy end class Operation < ActiveRecord::Base belongs_to :source default_scope :order => 'created_at DESC' end In Operation#index controller i have code for getting data (generated by scaffolding) #operations = Operation.all And piece of view operations/index.html.erb also generated by scaffolding <% #operations.each do |operation| %> <tr> <td><%= operation.source_id %></td> <td><%= operation.comment %></td> </tr> <% end %> Now I want to use source.name instead of *operation.source_id* I tried to do: -replace operation.source_id to operation.sources.name # doesn't work -tried to using :joins, and can't get Sources table fields irb(main):057:0> Operation.first( :joins => :source ) => #<Operation id: 2088, source_id: 1, summ: 10.0, comment: "", created_at: "2011-01-01 07:39:45", updated_at: nil> or irb(main):063:0> Operation.first( :joins => 'INNER JOIN sources ON operations.source_id = sources.id' ) => #<Operation id: 2088, source_id: 1, summ: 10.0, comment: "", created_at: "2011-01-01 07:39:45", updated_at: nil> How I must properly use :joins for get additional field? Or there is another approach to get combined tables data. And why in the operations/show.html.erb i can use <%= #operation.source.name %> and successfully get source.name, but in the *operations/index.html.er*b can't
<% #operations.each do |operation| %> <tr> <td><%= operation.source.name %></td> <td><%= operation.comment %></td> </tr> <% end %> I'd also recommend changing your #index method to use an includes statement to avoid an N+1 situation (i.e. running a separate database query for each individual operation's source). #operations = Operation.includes(:source).all
Solved: opearions#index #operations = Operation.all :joins => :source, :select => '*' operations/index.html.erb <% #operations.each do |operation| %> <tr> <td><%= operation.name %></td> ...