I have a question about updating one-to-many fields using simple_form field_for method
I have 2 models, Company and Clients, which has a one-to-many relationship.
I displayed clients using field_for, but for UI reason, I had to called it twice.
But for some reason, the index of the input fields was given a different value. Below is my code
<%= simple_form_for #company do |f| %>
<table>
<tr>
<td>
<%= f.input :name, label: 'Company name: ' %>
<%= f.simple_fields_for :clients do |client| %>
<%= client.input :name, label: 'Client names: ' %>
<% end %>
<%= f.input :info, label: 'Company info: ' %>
</td>
<td class="span2 clients_desc">
<%= f.simple_fields_for :clients do |client| %>
<%= client.input :description, label: 'Client description: ' %>
<% end %>
</td>
</tr>
</table>
<% end %>
Say if I had 3 clients, the output for the name of the input fields became
company[client_attributes][0][name], company[client_attributes][1][name], company[client_attributes][2][name]
and
company[client_attributes][3][description], company[client_attributes][4][description], company[client_attributes][5][description]
This result in duplicating clients during store. How do I solve this?
An easy workaround would be "caching" the form fields like so:
# ...
<%= f.simple_fields_for :clients do |client| %>
<%= client.input :name, label: 'Client names: ' %>
<% client_description_input = client.input :description, label: 'Client description: ' %>
<% end %>
# ...
<%= client_description_input %>
# ...
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 %>
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') %>
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.
I have the following code but can't render color as expected. When I render item.color I get #<Color:0x007ffce487a648>for example. If I render item.color.map(&:name) I get undefined method map for #<Color:0x007ffce6616918>
<% #this_week_orders.each do |order| %>
<tr style="font-weight:bold;">
<td><%= link_to "Order #{order.id}", order_path(order) %></td>
<td><%= l order.date, :format => :long %></td>
<td><%= pluralize(order.items.count, "item") %></td>
<td><%= number_to_currency(order.total_price) %></td>
<tr>
<% for item in order.items %>
<tr>
<td><li><%= item.product.name %></li></td>
<td><%= item.color %></td>
</tr>
<% end %>
<% end %>
Order has_many :items
Item belongs_to :order
Item belongs_to :product
Item belongs_to :color
scope :this_week, lambda { where("date > ?", 7.days.ago) }
Order controller
def this_week
#this_week_orders = Order.this_week.all
respond_to do |format|
format.html # index.html.erb
end
end
#<Color:0x007ffce487a648> reperesents an object of class Color (not a collection of color objects, whereupon it would make sense to use map). If Color has a name attribute, just write <%= item.color.name %>.
map is for use on an Array. item.color only returns one object. Use:
<%= item.color.name %>
if Color is a class like it appears to be you need to set the color value:
Something like:
<%= item.color.name %>
or whatever your value for the color is.