Rails has_many :through and collection_select with multiple - ruby-on-rails

I have the following problem using a has_many :through many-to-many relation in a multi-select via collection_select :multiple => true. I have Suppliers who deliver many Ingredients which can be delivered by many Suppliers. Have a look:
The Ingredient model:
class Ingredient < ActiveRecord::Base
has_many :ingredient_suppliers
accepts_nested_attributes_for :ingredient_suppliers, :allow_destroy => true
has_many :suppliers, :through => :ingredient_suppliers
end
The Supplier model:
class Supplier < ActiveRecord::Base
has_many :ingredient_suppliers
has_many :ingredients, :through => :ingredient_suppliers
end
The relationship Entity:
class IngredientSupplier < ActiveRecord::Base
belongs_to :ingredient
belongs_to :supplier
end
And this is the form. Note that I could not get it to work without specifying the :name:
<%= form_for(#ingredient) do |f| %>
<%= f.fields_for :suppliers do |supplier_fields| %>
<%= supplier_fields.collection_select (:supplier_ids,
Supplier.all(:order=>"name ASC"),
:id, :name,
{:selected => #ingredient.supplier_ids,
:include_blank => true},
{:multiple => true,
:name => 'ingredient[supplier_ids]'}) %>
<% end %>
<% end %>
If I remove the :name, then I get this error message:
Supplier(#-617951108) expected, got Array(#-608411888)
Request
Parameters:
{"commit"=>"Anlegen",
"authenticity_token"=>"MuEYtngwThharmM1KaAbH8JD3bScXiDwj0ALMytxl7U=",
"_method"=>"put",
"utf8"=>"✓",
"id"=>"1",
"ingredient"=>{"name"=>"Ingredient 1",
"nr"=>"00100",
"unit"=>"kg",
"mol_per_unit"=>"2000,
00000",
"description"=>"",
"suppliers"=>{"supplier_ids"=>["1",
"2"]}}}
The problem now is, that the PUT parameters only contain one supplier_id instead of an array of supplier_ids:
"ingredient"=>{"name"=>"Rohstoff 3", "nr"=>"00300", "unit"=>"Stk.", "mol_per_unit"=>"0,00000", "description"=>"", "supplier_ids"=>"2"}

I've got the problem solved. In this case, using fields_for was the error. The solution is using a collection_select, like this:
<%= collection_select(:ingredient, :supplier_ids,
Supplier.all(:order=>"name ASC"),
:id, :name, {:selected => #ingredient.supplier_ids, :include_blank => true}, {:multiple => true}) %>

Related

ActiveRecord::AssociationTypeMismatch in RoastsController#create

This is a new error to me, and struggling to resolve it. It also states: Roaster(#70130698993440) expected, got "1" which is an instance of String(#70130675908140)
It's highlighting my create method in my Roasts Controller:
def create
#roast = Roast.new(roast_params)
The scenario is that I'm trying to create a triple nested form. for three models Roasts Countries and Regions where roasts has many countries and countries has many regions.
I'm assuming there is something wrong with the roast params, but I can see what it is. I have added the associations there for the nested models
def roast_params
params.require(:roast).permit(:roaster, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, :countries_attributes => [:country_name, :regions_attributes => [:region_name]])
end
my form
<div class="form-group">
<%= form.fields_for :countries do |countries_form| %>
<%= countries_form.label :country %>
<%= countries_form.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= form.fields_for :regions do |regions_form| %>
<%= regions_form.label :region %>
<%= regions_form.text_field :region_name, class: "form-control" %>
<% end %>
<% end %>
</div>
Roast Controller
...
def new
#roast = Roast.new
#roast.countries.build.regions.build
end
...
roast model
class Roast < ApplicationRecord
has_many :tastings
has_many :countries
has_many :notes, through: :tastings
has_many :comments, as: :commentable
belongs_to :roaster
accepts_nested_attributes_for :countries
country model
class Country < ApplicationRecord
has_many :regions, inverse_of: :country
accepts_nested_attributes_for :regions
belongs_to :roasts
region model
class Region < ApplicationRecord
belongs_to :country
I've nested the regions params in the country params, is that correct? I also saw on SO other issues with suggestions for setting config.cache_classes to true in development.rb but that didn't help here.
Update
So looking at this further, I believe it's not related to the nested forms, but rather a collection_select I'm using.
<%= form.label :roaster, class: 'control-label' %>
<%= form.collection_select(:roaster, Roaster.order(:roaster_name).all, :id, :roaster_name, prompt: true, class: "form-control") %>
So this select is pulling the roaster_name from a model called Roaster.
My params now look like the below:
params.require(:roast).permit(:roaster_name, :roaster, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, :countries_attributes => [:country_id, :country_name, :regions_attributes => [:region_id, :region_name]])
And looking at the console when submitting the form, it seems that just the :id of Roaster is getting passed, rather than the value of :roaster_name.
{"utf8"=>"✓",
"authenticity_token"=>"EG+zty85IiVsgipm1pjSAEZ7M66ELWefLq8Znux+cf89sSnVXxielRr1IaSS9+cJvdQD8g1D4+v2KqtKEwh6gw==",
"roast"=>{"roaster"=>"1", "name"=>"Espress", "countries_attributes"=>{"0"=>{"country_name"=>"UK"}}, "regions"=>{"region_name"=>"Highlands"}, "bestfor"=>"", "roast"=>"", "tastingnotes"=>""},
"commit"=>"Create Roast"}
Can't work this out
ActiveRecord::AssociationTypeMismatch is raised when an association-setter (Roast#roaster= in this case) is called with a value that is not an instance of the expected class. Roaster was expected, got String.
The issue seems to be with passing roaster in as a param, which is "1" (String) in your example. I'm guessing this is actually an ID of a Roaster, the form code in the question does not show it.
Perhaps you meant to permit and pass a roaster_id param?
def roast_params
params.require(:roast).permit(:roaster_id, # ...
end

Rails 4 collection_select ordering

I am trying to order my collection_select dropdown by name instead of the default ID.
I have searched for a way to do this in Rails 4 but haven't found the solution. My code is:
<%= f.collection_select(:material_id, Material.order('name ASC').all, :id, :name) %>
This still returns a list ordered by ID. The models I'm using are:
Glaze.rb
has_many :ingredients
has_many :materials, :through => :ingredients
Ingredients.rb
belongs_to :glaze
belongs_to :material
Material.rb
has_many :ingredients
has_many :glazes, :through => :ingredients
Try this one, It should work. Will be passed name and attribute value with c.id
<%= f.select :material_id, Material.order('name ASC').map {|c| [c.name, c.id] },
{prompt:"Choose Material"}, class: "form-control" %>

rails how get related id on view page

i'm trying to make this conditional:
<% if current_boutique.boutique_kind(3) %>
Brand: <span><%= current_boutique.name %></span>
<% else %>
<%= p.input :brand_id, :as => :select, :collection=> Brand.find(:all, :order=>:name).collect{ |b| [b.name,b.id, b.name]},
:label => "Marca", :prompt => 'Select Brand', :required => true %>
<% end %>
but the boutique_kind(3) show all boutiques! how i just get the boutiques with boutiques_kind id 3 method!
boutiqueKind Controller
def show
#boutique_kind = BoutiqueKind.find(params[:id])
end
boutiqueKind model
attr_accessible :kind, :slug
has_many :boutiques
has_many :products, :through => :boutiques
#belongs_to :gender
accepts_nested_attributes_for :boutiques
attr_accessible :boutiques, :boutiques_attributes, :kind
Boutique Controller
class Boutique < ActiveRecord::Base
belongs_to :user
belongs_to :boutique_kind
end
You should be able to find the boutique by ID with:
BoutiqueKind.find(3)
If I'm misunderstanding, and id is not a unique id (in which case I suggest you rename the column to something other than id), you can get all records where a certain field == a specific value with:
BoutiqueKind.where(id: 3)

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 :)...

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