accept nested attributes for has_many relationship - ruby-on-rails

Below are my two model classes
class Patient < ActiveRecord::Base
belongs_to :user, :dependent => :destroy
has_many :enrollments, :dependent => :destroy
has_many :clients, :through => :enrollments
accepts_nested_attributes_for :user
accepts_nested_attributes_for :enrollments
attr_accessible :user_attributes,:enrollments_attributes, :insurance
end
class Enrollment < ActiveRecord::Base
belongs_to :client
belongs_to :patient
attr_accessible :client_id, :patient_id, :patient_id, :active
end
In my patient form I would like to have a multi select box where a patient can be assigned to clients. Is there a way this can be done so I don't have to have any logic in the
controller except for
#patient = Patient.new(params)
#patient.save
I have tried this:
<%= patient_form.fields_for :enrollments do |enrollments_fields| %>
<tr>
<td class="label">
<%= enrollments_fields.label :client_id %>:
</td>
<td class="input">
<%= enrollments_fields.collection_select(:client_id, #clients, :id, :name, {}, :multiple => true) %>
</td>
</tr>
<% end %>
But it only saves the first client. If I remove the multiple part, it functions but I can only select 1 client!
The html value of the select is:

I ended up doing the following:
<%= check_box_tag "patient[client_ids][]", client.id, #patient.clients.include?(client) %>
I am not sure if this is the best way...any comments (I had to update my model to include attr_accessible :client_ids

In Rails 3 (not sure about previous versions) you don't even need to use accepts_nested_attributes_for to accomplish this. You can simply remove all the view code you listed and replace it with the following:
<%= patient_form.select(:client_ids, #clients.collect {|c| [ c.name, c.id ] }, {}, {:multiple => true})%>
Rails will do its magic (because of you named the select "client_ids") and it will just work.

Instead of
:client_id
in the collection_select, try
"client_id[]"
The second form specifies that you're accepting an array of IDs for the attribute rather than a single one.
Here's a good resource on the usage of the select helpers in forms: http://shiningthrough.co.uk/Select-helper-methods-in-Ruby-on-Rails

Related

RoR - Searching gem for uploading files

I'm searching a gem (like paperclip or carrierwave) that allows you to upload images. But I want a relationship between the image and the otherside:
I have a table day
And I want a own table for the images so that at the and I'm going to have an has_many belongs_to relationship.
So one day has many images
any suggestions?
If I understand you correctly, you may want to look at the has_many :through relationship for this. We have this working with Paperclip & allows you to have many images to one record:
#app/models/day.rb
Class Day > ActiveRecord::Base
has_many :day_images, :class_name => "DayImage"
has_many :images, :class_name => "Image", :through => :day_images, dependent: :destroy
accepts_nested_attributes_for :day_images, :allow_destroy => true
end
#app/models/day_image.rb
Class DayImage > ActiveRecord::Base
belongs_to :day, :class_name => "Day"
belongs_to :image, :class_name => "Image"
accepts_nested_attributes_for :image, :allow_destroy => true
end
#app/models/image.rb
Class Image > ActiveRecord::Base
has_many :day_images, :class_name => "DayImage"
has_many :days, :class_name => "Day", :through => :day_images, dependent: :destroy
end
The join model would then look like this:
day_images table
id | day_id | image_id | extra attribute | extra attribute | created_at | updated_at
This would allow you to allocate images to the day model using the accepts_nested_attributes_for, like this:
Nested Models
Nested models are pretty tough to get right at first, but get easier the more you do them
Using the models I outlined above, you'll have to add several important factors to make accepts_nested_attributes_for work for you. Here's how:
#app/controllers/days_controller.rb
def new
#day = Day.new
#day.day_images.build.build_image
end
def create
#day = Day.new(day_params)
#day.save
end
private
def day_params
params.require(:day).permit(:day, :variables, day_images_attributes: [:image_id, :extra_attributes, :in, :join, :model, image_attributes: [:image]])
end
This will allow you to create a form like this:
#app/views/days/new.html.erb
<%= form_for #day do |f| %>
<%= f.text_field :day_attribute %>
<%= f.fields_for :day_images do |day_image| %>
<%= day_image.text_field :caption %>
<%= day_image.collection_select(:image_id, Image.where(:user_id => current_user.id), :id, :image_name, include_blank: 'Images') %> --> this will allow you to assign images
<%= day_image.fields_for :image do |i| %>
<%= i.file_field :image %> --> uploads new image
<% end %>
<% end %>
<% end %>
This is all based off live code. If you need any more help, let me know!

Rails displaying multiple same records

I am providing my active records below. In view/users/show I want to display any project the user is working on, through blueprints. When a user adds multiple blueprints to a project, the project is showing up multiple times. I tried some validate_uniqueness options to no avail.
class Blueprint < ActiveRecord::Base
attr_accessible :id, :name, :project_id, :user_id, :loc
belongs_to :user
belongs_to :project
has_many :comments
end
class Project < ActiveRecord::Base
attr_accessible :id, :name
has_many :blueprints
has_many :users, :through => :blueprints
has_many :comments
end
class User < ActiveRecord::Base
attr_accessible :id, :name
has_many :blueprints
has_many :projects, :through => :blueprints
end
Here is the view code that is displaying multiple values of the same project.
<% #user.blueprints.each do |blueprint| %>
<tr>
<td><%= link_to blueprint.project.name, project_path(blueprint.project) %></td>
</tr>
<% end %>
Thanks!
Try setting uniq option to true in user's projects relation like this
class User < ActiveRecord::Base
has_many :projects, :through => :blueprints, :uniq => true
end
Since you already have the projects association in the User, why don't you loop through the user's projects instead of the blueprints.
<% #user.projects.each do |project| %>
<tr>
<td><%= link_to project.name, project_path(project) %></td>
</tr>
<% end %>

Rails 3.2: multiple nested data from one model

How to create form and action for multiple nested attributes if:
LineItem:
has_many :item_options, :dependent => :destroy
has_many :product_options, :through => :item_options
ProductOption:
belongs_to :product
belongs_to :option
has_many :item_options
has_many :line_items, :through => :item_options
ItemOption:
attr_accessible :line_item_id, :product_option_id
belongs_to :line_item, :foreign_key => "line_item_id"
belongs_to :product_option,:foreign_key => "product_option_id"
When I'm creating new LineItem, I need to create new ItemOption(s). This is my form:
<%= form_for(LineItem.new) do |f| %>
<%= f.hidden_field :product_id, value: #product.id %>
<%= f.fields_for :item_options do |io| %>
<% #product.options.uniq.each do |o| %>
<%= o.name %>:
<%= io.collection_select :product_option_id, o.product_options.where(:product_id => #product.id), :id, :value %>
<% end %>
<%= f.submit %>
<% end %>
When I'm clicking on Add To Cart, I've get:
ItemOption(#70296453751440) expected, got Array(#70296430421140)
When Adding accepts_nested_attributes_for :item_options to LineItem, my selects not diplayed :(
With
<%= select_tag "product_option_id", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
#item_options not created:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"/WM5/MqPn1yCxjKWoJQmjfko2pR4RiYV0S2KeTTpA3w=", "line_item"=>{"product_id"=>"1"}, "product_option_id"=>"5", "commit"=>"add"}
And last one, I've create action like this:
#line_item = LineItem.new(params[:line_item])
#line_item.item_options.build
....
Where am I wrong? :( I'm totally confused.
ps. similar question Rails 3.2 has_many through form submission
This is form:
Looks this line:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"/WM5/MqPn1yCxjKWoJQmjfko2pR4RiYV0S2KeTTpA3w=", "line_item"=>{"product_id"=>"1"}, "product_option_id"=>"5", "commit"=>"add"}
The parameter product_option_id is outside line_item hash, and will be inside. Maybe you need write the select like this:
<%= select_tag "line_item[product_option_id]", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
I'm not sure, but maybe is this. Maybe I need more information, like the exact line where is failing.
Extra, the :foreign_key => "line_item_id" and :foreign_key => "product_option_id" are not necesary, because, the belongs_to model name is the same and will use these foreign_key. From api.
Specify the foreign key used for the association. By default this is
guessed to be the name of the association with an “_id” suffix. So
a class that defines a **belongs_to :person** association will use
“person_id” as the default :foreign_key. Similarly, belongs_to
:favorite_person, :class_name => "Person" will use a foreign key of
“favorite_person_id”.
Edit
Sorry, the unknown attribute: product_option_id is because the attribute name is product_option_ids, and is an array, not a unique value. For a has_many relationship, the column name is collection_singular_ids, and the select should be:
<%= select_tag "line_item[product_option_ids][]", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
This should work, I think :)...

Rails has many through relationships

I am using rails has_many through options and not sure if I am doing something wrong here. I would like for a player to create a season and when a player is about to create a season it will show a select menu of all the seasons I have created in years/new. So far that part has worked great but when a player try's to save the season rails does not save it. I am not sure if my association is correct or if I am doing something wrong? Is there any reason why this is not working?
error
No association found for name `season_year'. Has it been defined yet?
season.rb
class season < ActiveRecord::Base
belongs_to :player
has_many :quarters
has_many :years , :through => :quarters
attr_accessible :season_year_attributes
accepts_nested_attributes_for :season_year
end
quarter.rb
class Quarter < ActiveRecord::Base
belongs_to :player
belongs_to :year
belongs_to :season
end
year.rb
class Year < ActiveRecord::Base
attr_accessible :season_year, :season_name
has_many :quarters
has_many :seasons, :through => :quarters
end
player.rb
class player < ActiveRecord::Base
has_many :seasons, :through => :quarters
has_many :years, :through => :quarters
end
_season-form.html.erb
<%= form_for(#season) do |f| %>
<div class="field">
<%= f.label :season %>
<%= f.text_field :season_name %>
</div>
<%= f.fields_for :years do |year| %>
<%= select("season", "year_ids", Year.all.collect {|p| [ p.season_year, p.id ] }, { :include_blank => true }) %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Based on your models, I believe you need to change this:
accepts_nested_attributes_for :season_year
to this:
accepts_nested_attributes_for :years
When you accept nested attributes it is for a Model and not a property of a model (season_year is an attribute of the year model versus accepting the nested attributes for the actual model, Year).
EDIT:
In the Season model, I added year_ids to the attr_accessible expression:
attr_accessible :season_year_attributes, :year_ids
I also altered the season form so that the output of the select list for years was only this:
<%= select("season", "year_ids", Year.all.collect {|p| [ p.title, p.id ] }, { :include_blank => true }) %>
You don't have any season_year in your Season class, that is the answer.
Did you intend to have this as an association?

Assigning a nested attribute with Formtastic

I've been trying to figure this one out for a while but still no luck. I have a company_relationships table that joins Companies and People, storing an extra field to describe the nature of the relationship called 'corp_credit_id'. I can get the forms working fine to add company_relationships for a Person, but I can't seem to figure out how to set that modifier field when doing so. Any ideas?
More about my project: People have many companies through company_relationships. With that extra field in there I am using it to group all of the specific relationships together. So I can group a person's Doctors, Contractors, etc.
My models:
Company.rb (abridged)
class Company < ActiveRecord::Base
include ApplicationHelper
has_many :company_relationships
has_many :people, :through => :company_relationships
Person.rb (abridged)
class Person < ActiveRecord::Base
include ApplicationHelper
has_many :company_relationships
has_many :companies, :through => :company_relationships
accepts_nested_attributes_for :company_relationships
company_relationship.rb
class CompanyRelationship < ActiveRecord::Base
attr_accessible :company_id, :person_id, :corp_credits_id
belongs_to :company
belongs_to :person
belongs_to :corp_credits
end
My form partial, using formtastic.
<% semantic_form_for #person do |f| %>
<%= f.error_messages %>
<% f.inputs do %>
...
<%= f.input :companies, :as => :check_boxes, :label => "Favorite Coffee Shops", :label_method => :name, :collection => Company.find(:all, :conditions => {:coffee_shop => 't'}, :order => "name ASC"), :required => false %>
So what I would like to do is something like :corp_credit_id => '1' in that input to assign that attribute for Coffee Shop. But formtastic doesn't appear to allow this assignment to happen.
Any ideas on how to do this?
Are you looking for something like
<% semantic_form_for #person do |form| %>
<% form.semantic_fields_for :company_relationships do |cr_f| %>
<%= cr_f.input :corp_credit_id %>
<% end %>
It is in the documentation

Resources