Ruby on Rails 4
My Form was working great when I had Product.all:
<div id="ip_voice">
<%= f.label :product_id %><br>
<%= f.collection_select :product_id, Product.all, :id, :name, {prompt: "Select a product"}, {class: "form-control input-lg"} %>
</div>
I changed it to a Product.where so I could show different options based on another selection, but this is not sending the :id of the Product. I am new to Rails 4.
<div id="ip_voice">
<%= f.label :product_id %><br>
<%= f.collection_select :product_id, Product.where({ category: "ip_voice" }), :id, :name, {prompt: "Select a product"}, {class: "form-control input-lg"} %>
</div>
My log, shows the product_id field as "" which is not allowed.
Started POST "/mc_question" for x at 2014-04-25 10:05:13 -0700
Processing by QuestionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"x=", "question"=>{"content"=>"what is going on", "category"=>"ip_video_telephon
y", "product_id"=>"", "active"=>"1", "question_type"=>"MC", "answers_attributes"=>{"0"=>{"content"=>"what", "correct"=>"0"}, "1"=>{"content"=>"is", "correct"=>"1"}, "2"=>{"
content"=>"up", "correct"=>"0"}, "3"=>{"content"=>"", "correct"=>"0"}}}, "commit"=>"Create Question"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'x' LIMIT 1
(0.1ms) begin transaction
(0.0ms) rollback transaction
The div ip_voice is one of six. Onle one is show() the others are hide(). Don't think that matters though. Like this:
<div id="ip_video_surveillance">
<%= f.label :product_id %><br>
<%= f.collection_select :product_id, Product.where({ category: "ip_video_surveillance" }), :id, :name, {prompt: "Select a product"}, {class: "form-control input-lg"} %>
</div>
<div id="ip_video_telephony">
<%= f.label :product_id %><br>
<%= f.collection_select :product_id, Product.where({ category: "ip_video_telephony" }), :id, :name, {prompt: "Select a product"}, {class: "form-control input-lg"} %>
</div>
HTML Names are the same:
<div id="ip_voice">
<label for="question_product_id">Product</label><br>
<select class="form-control input-lg" id="question_product_id" name="question[product_id]"><option value="">Select a product</option>
<option value="2">thisone</option>...
</div>
<div id="ip_video_surveillance">
<label for="question_product_id">Product</label><br>
<select class="form-control input-lg" id="question_product_id" name="question[product_id]"><option value="">Select a product</option>...
Any help appreciated.
If you have six f.collection_select :product_id then most likely they all have same name attribute for <select>. Try to check it in generated HTML.
In that case you have to use different names.
upd: Your question[product_id] passed as "question"=>{"product_id"=>""}
params quacks like a Hash. So all following values will override previuos:
> params = ActionController::Parameters.new(question: { product_id: 1 })
=> {"question"=>{"product_id"=>1}}
> params[:question][:product_id] = ""
=> ""
> params
=> {"question"=>{"product_id"=>""}}
Try giving it as a scope in your model and use that in collection_select
#=>product.rb
class Product < ActiveRecord::Base
scope :category, -> { where(category: "ip_voice") }
end
<div id="ip_voice">
<%= f.label :product_id %><br>
<%= f.collection_select :product_id, Product.category, :id, :name, {prompt: "Select a product"}, {class: "form-control input-lg"} %>
</div>
Edit
In your products_controller.rb assign the scope to an instance variable like this
def your_method
#product_categories = Product.category
end
and use in the form in place of Product.category
<div id="ip_voice">
<%= f.label :product_id %><br>
<%= f.collection_select :product_id, #product_categories, :id, :name, {prompt: "Select a product"}, {class: "form-control input-lg"} %>
</div>
Related
I am trying to use a collection_select for state just to filter cities, but I don't want to save the state_id in db. My "college" model has only city and college field. That's why it's throwing while instantiating :state_id I believe, I am new to rails. I am not able to figure it out. :(
<%= form_for #college do |f| %>
<div class="form-group">
<%= f.label "Select city"%>
<%= f.collection_select(:state_id, State.all, :id, :state, {}, {class: "form-control"})%>
</div><br>
<div class="form-group">
<%= f.label :city_id, "Select city"%>
<%= f.collection_select(:city_id, City.all, :id, :city, {}, {class: "form-control"})%>
</div><br>
<div class="form-group">
<%= f.label :college, "college Name"%>
<%= f.text_field :college, class: "form-control", placeholder: "Enter city name", required: true%>
<br>
</div>
<div class="form-group">
<%= f.submit class: "btn btn-primary"%>
</div>
<% end %>
just define state_id attribute accessor in your college.rb model :
attr_accessor :state_id
inside your model you should define state_id as attr_accessor like :-
class College
attr_accessor :state_id
end
I have a CRUD application where you can create pizzas. You can choose the base, the size and the toppings with select elements. For this I used collection_select.
However, when a pizza is created, these attributes are not assigned to the new object.
This is my form:
<div class="field">
<%= f.label :size_id %><br>
<%= collection_select(:size, :pizza_id, Size.all, :id, :name) %>
</div>
<div class="field">
<%= f.label :crust_id %><br>
<%= collection_select(:crust, :pizza_id, Crust.all, :id, :name) %>
</div>
<div class="field">
<%= f.label :toppings %><br>
<%= collection_select(:toppings, :pizza_id, Topping.all, :id, :name, {}, { :multiple => true }) %>
</div>
The controller, generated with scaffold:
class PizzasController < ApplicationController
before_action :set_pizza, only: [:show, :edit, :update, :destroy]
...
def create
#pizza = Pizza.new(pizza_params)
...
end
...
private
def pizza_params
params.require(:pizza).permit(:name, :price, :size, :crust, :topping => [])
end
end
When I look at the parameters in the log, I can see this:
Processing by PizzasController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5oiP9EzpTC1fOVGSxv6MXF1qg786Vy3BtnIzEmCh19s=", "pizza"=>{"name"=>"Small pizza", "price"=>"10"}, "crust"=>{"pizza_id"=>"1"}, "toppings"=>{"pizza_id"=>["", "1", "2"]}, "commit"=>"Create Pizza"}
It looks like the attributes that are not being saved are not included in the pizza key, that's why they are not being assigned to the object.
I noticed the format of the input's name should be pizza[attribute] so it goes to the correct hash. So I tried something like this:
<%= collection_select(:size, :pizza_id, Size.all, :id, :name) %>
These are the parameters:
Processing by PizzasController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5oiP9EzpTC1fOVGSxv6MXF1qg786Vy3BtnIzEmCh19s=", "pizza"=>{"name"=>"Small pizza", "price"=>"10", "size"=>"1"}, "crust"=>{"pizza_id"=>"1"}, "toppings"=>{"pizza_id"=>["", "1", "2"]}, "commit"=>"Create Pizza"}
It doesn't work because it is not transforming the size into the proper class.
What can I do?
you're bit incorrect with params order. It should look like
<div class="field">
<%= f.label :size_id %><br>
<%= collection_select(:pizza, :size_id, Size.all, :id, :name) %>
</div>
<div class="field">
<%= f.label :crust_id %><br>
<%= collection_select(:pizza, :crust_id, Crust.all, :id, :name) %>
</div>
<div class="field">
<%= f.label :toppings %><br>
<%= collection_select(:pizza, :topping_ids, Topping.all, :id, :name, {}, { :multiple => true }) %>
</div>
first parameter is hash root and then attribute
and change params method to be
def pizza_params
params.require(:pizza).permit(:name, :price, :size_id, :crust_id, :topping_ids)
end
I understand that you want all the keys included in the pizza key. This is what you need to do:
<%= collection_select(:pizza, :crust_id, Crust.all, :id, :name) %>
<%= collection_select(:pizza, :topping_ids, Topping.all, :id, :name, {}, { :multiple => true }) %>
If you look at the documentation for collection_select, it states that the first parameter is the key(which is pizza in your case) and the next parameter is the attribute name in the select box(crust/toppings)
I have two collection_select field in my form. One is to select category and the other is to select subcategory. I want the subcategory field to populate as per the category gets selected. I someone select category 1 then the subcategories belong to category 1 will be populated in the second collection_select field. I'm not sure what to do. What modifications I need in the following code I tried.
<div class="field">
<%= f.label :category_id %><br>
<%= f.collection_select(:category_id, Category.find(:all), :id, :name) %>
</div>
<div class="field">
<%= f.label :subcategory_id %><br>
<%= f.collection_select(:subcategory_id, Subcategory.where(category_id: :category_id), :id, :name) %>
</div>
You need to ajax to get this functionality
Try this Example:
form.html.erb
<script>
$(document).ready(fnction(){
$('#category_id').change(function(){
var value = $(this).val()
$.ajax({
type: 'POST',
url: 'options',
data: {id: value},
success: function(data){
$('#subcategory').html(data)
}
})
})
})
</script>
<div class="field">
<%= f.label :category_id %><br>
<%= f.collection_select(:category_id, Category.find(:all), :id, :name) %>
</div>
<div id="subcategory"></div>
controller:
def options
id = params[:id]
#subcategory = Subcategory.where(:category_id => id)
render :partial => 'options'
end
_options.html.erb:
<%= f.label :subcategory_id %><br>
change this line
<%= f.collection_select(:subcategory_id, #subcategory, :id, :name) %>
to
<%= f.input :subcategory_id, #subcategory %>
and finally in Routes.rb
post '/options' => 'categories#options'
You have two ways:
Use jquery. Something like that -
$(select_category).on('change', function(){ update_subcategory_options() })
where update_subcategory_options() - ajax request or another code.
Or use collection select with group (http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/option_groups_from_collection_for_select)
I have a few models Score ScoreAuthority ScoreColor and ScoreType. Score has_one authority, color, and type. Authority, color, and type each belong_to score. I am having trouble creating the form for Score.
I want users to create this relationship from Scores and everyone seems to handle only the reverse scenario creating from authorities, colors, types forms. What I mean specifically is for example:
Authorities
- foo
- bar
Colors
- red
- blue
I want the use to go into Score, chose to create a new score and then select foo from the drop down list, blue from the colors list, enter a score and submit. Authorities, colors and types will not change much and it would make any sense for the user to select Score from each of those.
When I currently do that I get the following error:
ScoreAuthority(#2248480380) expected, got String(#2155957040)
score/_form.html.erb
<%= form_for #score, :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :product_id, "Products", :class => 'control-label' %>
<div class="controls">
<%= f.collection_select(:product_id, Product.order(:name), :id, :name) %>
</div>
</div>
<div class="control-group">
<%= f.label :score_authority, "Score Authority", :class => 'control-label' %>
<div class="controls">
<%= f.collection_select :score_authority, ScoreAuthority.order(:name), :id, :name, {}, {:class=>'chosen'} %>
</div>
</div>
<div class="control-group">
<%= f.label :score_type, "Score Types", :class => 'control-label' %>
<div class="controls">
<%#= f.collection_select(:score_type, ScoreType.order(:name), :id, :name) %>
<%= f.collection_select :score_type, ScoreType.order(:name), :id, :name, {}, {:class=>'chosen'} %>
</div>
</div>
<div class="control-group">
<%= f.label :score_color, "Score Types", :class => 'control-label' %>
<div class="controls">
<%= f.collection_select :score_color, ScoreColor.order(:name), :id, :name, {}, {:class=>'chosen'} %>
</div>
</div>
<div class="control-group">
<%= f.label :notation, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :notation, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :value, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :value, :class => 'text_field' %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
scores_path, :class => 'btn' %>
</div>
<% end %>
score_authorities, score_colors, score_types tables all have score_id as a column. Each of these models also has belongs_to :score.
The score model
has_one :score_authority
has_one :score_type
has_one :score_color
Not sure what I am doing wrong here, any help would be appreciated. Thanks!
you should use :score_authority_id instead of :score_authority in form
<%= f.collection_select :score_authority_id, ScoreAuthority.order(:name), :id, :name, {}, {:class=>'chosen'} %>
<%= f.collection_select :score_color_id, ScoreColor.order(:name), :id, :name, {}, {:class=>'chosen'} %>
<%= f.collection_select :score_color_id, ScoreColor.order(:name), :id, :name, {}, {:class=>'chosen'} %>
see this How do I create the view for the has_one association? for more detail
or you can try
class Score
has_one :score_authority
accepts_nested_attributes_for :score_authority
end
<%= form_for #score ... do |f| %>
...
<%= f.fields_for :score_authority do |b| %>
<%= b.collection_select :id, ScoreAuthority.all, :id, :name %>
...
<% end %>
...
<% end %>
I have the following (and working) dynamic menu / dropdown which allows you to select a property type and then a property subtype with a regular rails form:
properties.js.coffee
jQuery ->
prop_sub_types = $('#property_prop_sub_type_id').html()
$('#property_prop_type_id').change ->
prop_type = $('#property_prop_type_id :selected').text()
escaped_prop_type = prop_type.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/#])/g, '\\$1')
options = $(prop_sub_types).filter("optgroup[label='#{escaped_prop_type}']").html()
if options
$('#property_prop_sub_type_id').html(options)
else
$('#property_prop_sub_type_id').empty()
_form.html.erb
<%= form_for(#property) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :prop_type_id, 'Property Type' %><br />
<%= f.collection_select :prop_type_id, PropType.order(:name), :id, :name, :prompt => "-- Select Property Type --" %>
</div>
<div class="field">
<%= f.label :prop_sub_type_id, 'Property Subtype' %><br />
<%= f.grouped_collection_select :prop_sub_type_id, PropType.order(:name), :prop_sub_types, :name, :id, :name, :prompt => "-- Select Property Subtype --" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This works fine. However, I'd like to integrate this into a larger app that is already set up with the simple form gem. I'm also using twitter bootstrap via bootstrap-sass.
The closest I can get in my form is:
<div class="field">
<%= f.association :prop_type, :input_html => { :id => "prop_type_id", :class => "span5" }, :prompt => "-- Select Property Type --" %>
<%= f.association :prop_sub_type, :input_html => { :id => "prop_sub_type_id", :class => "span5" }, :prompt => "-- Select Property Subtype --" %>
</div>
Note: I had to change :prop_type_id to :prop_type to keep the app from throwing errors.
But this is not working - the second drop down won't map to the first. I a doing something wrong in my java/coffeescript? Is there such a thing as 'grouped_association' or something along those lines for the second dropdown?
Is this even doable, or should I convert the entire form back to the standard rails format?
UPDATE
I was able to get it to work but sticking the erb into divs as follows:
<div class="field">
<%= f.collection_select :prop_type_id, PropType.order(:name), :id, :name, :prompt => "-- Select Property Type --" %>
</div>
<div class="field">
<%= f.grouped_collection_select :prop_sub_type_id, PropType.order(:name), :prop_sub_types, :name, :id, :name, :prompt => "-- Select Property Subtype --" %>
</div>
You should have a look at the Group section in the simple_form_for github page. I was working on something similar to what you were doing and found this section. It gave me the direction that I needed to go. Instead of doing f.association which I used on other parts, I ended up using f.input with the :group_select and :group_method
f.input :country_id, collection: #continents, as: :grouped_select, group_method: :countries
from
simple_form_for github pag