Data-column in Rails form builder select - ruby-on-rails

How do you add a data-column to Rail's form builder select?
Here is the basic HTML that I want to reproduce.
<div class="input-group">
<select class="form-control" data-column="3">
</select>
</div>
Here is the code that I can't get right:
<div class="field">
<%= f.label :category %><br>
<%= f.select :category, {prompt: "Select Category"}, {class: "input-lg", :id => "category"}, data-column: 3 %>
</div>
I have tried putting data-column in the prompt section and in the class section.

You should use
"data-column" => 3
I thought the problem was only the data-column, this is the complete solution (it's not what you are trying to reproduce but I think this example is more detailed):
<%= f.select :category, [], { :include_blank => 'Select Category'}, {:class => 'input-lg', :id => 'category', "data-column" => 3} %>
to get:
<select class="input-lg" data-column="3" id="category" name="something[category]">
<option value="">Select Category</option>
</select>
If, instead, you are trying just to get the code you specified in your question, you can do:
<div class="input-group">
<%= f.select :category, [], {}, {:class => 'form-control', "data-column" => 3} %>
</div>

Related

Rails 4 where not sending id

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>

Ruby on Rails - form_for collection_select options not visable

I'm using a collection_select in a form_for however the options are not displaying in the browser (empty select box) but are present in the debugger view. (this happens in both chrome and IE10).
View:
<%= form_for(#lot) do |f| %>
<%= f.label :client_id, "Client" %>
<%= f.select :client_id, collection_select(:lot, :client_id, Client.all, :id, :org, :include_blank => "Please select") %>
Rendered page source:
<label for="lot_client_id">Client</label>
<select id="lot_client_id" name="lot[client_id]"></select>
<option value="">Please select</option>
<option selected="selected" value="1">Client 1</option>
<option value="2">client 2</option>
Controller:
def new
#lot = Lot.new(:client_id => 1)
end
Any insight would be much appreciated thanks,
you can try this as eg.
<%= f.collection_select(:category_id, Category.all,:id,:name, :required=>true) %>
collection_select is also a formHelper of sorts which returns both a select and options elements, try:
<%= f.collection_select(:lot, :client_id, Client.all, :id, :org, :include_blank => "Please select") %>
instead
You are rendering collection_select helper inside the select helper, which is wrong. You have to do it like this:
<%= f.collection_select(:client_id, Client.all, :id, :org, :include_blank => "Please select") %>

Convert grouped_collection_select to Simple Form in Rails dynamic menu?

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

Multiple values for collection_select

I am trying to have the following HTML code in my form:
<select name="user[language_ids][]">
<option value="">Please select</option>
<option value="1" selected="selected">English</option>
<option value="2">Spanish</option>
</select>
<select name="user[language_ids][]">
<option value="">Please select</option>
<option value="1" selected="selected">English</option>
<option value="2">Spanish</option>
</select>
To allow the User to select two languages when he signs up.
I have tried with this:
<%= f.label :languages %>
<%= f.collection_select(:language_ids, Language.all, :id, :name) %>
<%= f.collection_select(:language_ids, Language.all, :id, :name) %>
And also with this:
<%= f.label :languages %>
<%= f.collection_select(:language_ids[], Language.all, :id, :name) %>
<%= f.collection_select(:language_ids[], Language.all, :id, :name) %>
After revieweing the answers, I have tried with this:
<%= collection_select(:user, :language_ids, Language.all, :id, :name, {}, {:name => 'user[language_ids][]' }) %>
<%= collection_select(:user, :language_ids, Language.all, :id, :name, {}, {:name => 'user[language_ids][]' }) %>
But the problem here is that both of the selects have the same ID and also, they are not associated with the form builder f
Any thoughts on the best way to do so?
Try,
<%= f.collection_select(:language_ids, Language.all, :id, :name,{}, {:multiple => true}) %>
You can create a collection of fields by using
fields_for.
The two select will have the same id but
collection_select
takes an optional hash containings html options where you can set a custom id.
<%= f.fields_for :language_ids do |language| %>
<%= language.collection_select(nil, Language.all, :id, :name,
{include_blank: "Please select", selected: 1},
{id: :user_language_id_1}) %>
<%= language.collection_select(nil, Language.all, :id, :name,
{include_blank: "Please select", selected: 1},
{id: :user_language_id_2}) %>
<% end %>
generates the following output:
<select id="user_language_id_1" name="user[language_ids][]">
<option value="">Please select</option>
<option value="1" selected="selected">English</option>
<option value="2">Spanish</option>
</select>
<select id="user_language_id_2" name="user[language_ids][]">
<option value="">Please select</option>
<option value="1" selected="selected">English</option>
<option value="2">Spanish</option>
</select>
Since you wrote "user[language_ids][]" in the name attribute of your select, I'm forced to assume you want a multiple select box. You should do this:
f.collection_select (:language_ids, Language.all, :id, :name,
{:prompt => true}, {:multiple => true})
Not a very well documented feature, for sure.
EDIT: Looking further on your example and some of the answers, I would like to point out a few things:
Your example has the prompt "Please select" as first option of the select box, but then you want english to be "selected in both of your examples. If you want an option to be pre-selected which it as well the first option of the select box, then why do you have the prompt option? One uses it to force the user to choose something.
You wrote in one answer that you want multiple selects instead of a multiple select, reason why you don't want the :multiple => true solution. I'd still recommend you to use it, but maybe you really have a necessary use case. Therefore, I would recommend you to use the select_tag helper directly (I don't think you'll achieve that with form tag helpers):
select_tag "user[language_ids][]",
options_from_collection_for_select(Language.all, "id", "name"),
:prompt => true, :id => "user_language_ids"
key here is, the mutiple selects have to have different ids, which you will have to pass explicitly, so it'll be on your hands.
You should be able to do something like this:
<%= f.label :languages %>
<%= f.collection_select(:language_ids, Language.all, :id, :name, {}, {id => "language_1", :name => "user[language_ids][]"}) %>
<%= f.collection_select(:language_ids, Language.all, :id, :name, {}, {id => "language_2", :name => "user[language_ids][]"}) %>
Basically sending 2 (or more) fields with the same attribute doesn't work, because params will be turned into a hash : {language_ids: [1], language_ids: [2]} and since you have the same key the last one will override the previous one(s).
{a: 1, a: 2}[:a] #=> 2
To circumvent this problem you need to to create different attributes and then concatenate them in one. For this you'll need facade attributes in your model :
class Language
attr_writer :language_one_id, :language_two_id
before_save :gather_languages
def gather_languages
self.language_ids= [language_one_id, language_two_id]
end
# for the form to display chosen lang (idem with two)
def language_id
language_ids.first
end
end
# view/_form
=f.select :language_one_id, Language.all.map {|l| [l.name, l.id]}
=f.select :language_two_id, Language.all.map {|l| [l.name, l.id]}
But frankly I think you're making your life harder by going against conventions here (I'd use checkboxes instead).
You could add a "second_language" column to your table and then make it have the same content as the first language column.
You could use fields_for like this:
<%= form_for #user do |f| %>
...
<h2>Languages</h2>
<%= fields_for :languages do |lang_form| %>
<%= lang_form.collection_select :language_id, Language.all, :id, :name %>
<% end %>
..
<% end %>
On your controller, in your new or edit method, you can do this to accept 2 languages
2.times { #user.languages.build }
First of all you have to edit your user model:
user.rb
has_many :languages
accepts_nested_attributes_for :languages
Next generate model:
$> rails g model language user_id:integer name
language.rb
belongs_to :user
users_controller.rb (probably in 'new' action)
2.times do
language = #user.language.build
end
_form.html.erb
<%= form_for #user do |f| %>
<%= f.fields_for :languages do |lang| %>
<%= lang.label :name, "Name" %><br />
<%= lang.select :name, Language.all.collect {|l| [l.name, l.id]}, prompt: 'Please select' %><br />
<%= end %>
<p><%= f.submit "Submit" %></p>
<% end %>
Try This:
<%=select_tag "language_ids[]" options_for_select([['Please select','']]+Language.all.map{|ln|[ln.name,ln.id]})%>
uses the gem, gem "cocoon"
in the form of the model you want to add the field
<div class="form-group">
<%= f.fields_for :photoproducts do |forms_fields| %>
<% render partial: "shared/photoproducts_fields", locals: {f: forms_fields} %>
<% end %>
<%= link_to_add_association('+ Foto', f, :photoproducts, type: "button", class: "btn btn-primary btn-sm") %>
</div>
(In this example, I have a product template, which I'm adding photos to)
and then create a partial in a shared folder at the root of the project.
-
project / shared / _fotoproduto_fields.html.erb
<div class="nested-fields">
<%= link_to_remove_association('remove photo', f, type: "button", class: "btn btn-danger btn-sm") %>
<div class="photoproducts">
<div class="form-group">
<label class="control-label"><%= f.label :name %></label>
<%= f.text_field :name, class: "form-control", type: "text" %>
</div>
<div class="form-group">
<label class="control-label"> photo</label>
<%= f.file_field :files, class: "form-control" %><br/><br/>
</div>
</div>
</div>
this way you get a more dynamic form
remember to put parameters in the controllers for nested attributes, and put in the create method, a build of the model.
ex: #products.photoproducts.build

Refactoring a Rails view

I'm new to Rails development, so please bear with me. I'm creating a view that has several fields on it that look very similar. It's just begging to be refactored somehow but I haven't been able to figure it out. See code sample below:
<%= form_for(#tapelog) do |f| %>
<div class="container">
<div class="field span-16">
<div class="span-8 labelRight">
<%= f.label :client %>
</div>
<div class="span-8 last">
<%= f.collection_select :client_id, Client.find(:all), :id, :name,
{ :prompt => "Select a Client..." },
{ :class => "automatixSelect" } %>
</div>
</div>
<div class="field span-16">
<div class="span-8 labelRight">
<%= f.label :employer %>
</div>
<div class="span-8 last">
<%= f.collection_select :employer_id, Employer.find(:all), :id, :name,
{ :prompt => "Select an Employer..." },
{ :class => "automatixSelect" } %>
</div>
</div>
....
<% end %>
There are about 7 fields like that. I tried to put them all into partials just so I could reduce the clutter on this page but that errors out because 'f' is not defined. Any ideas on how I could reduce some of the clutter here? Any other tips in general on Ruby refactoring would also be welcome.
Thanks,
-- A.
If you want to use the 'f' in the subsequent partials, pass it as a parameter
<%= render :partial => :some_partial, :locals => { :f => f } %>
The first thing I'd do is rename the "f" local variable to "form" for clarity. Then, extracting the code to a partial is reasonable:
<div class="field span-16">
<div class="span-8 labelRight">
<%= form.label :employer %>
</div>
<div class="span-8 last">
<%= form.collection_select :employer_id, Employer.find(:all), :id, :name,
{ :prompt => "Select an Employer..." },
{ :class => "automatixSelect" } %>
</div>
</div>
It looks to me like this is a belongs_to relationship, so I might create a partial called "belongs_to" and render it like:
<%= render :belongs_to, :parent => :employer, :form => form %>
The idea is we'll have a local named "parent" that we can alter in the partial. Note that I used the shorthand partial syntax. It's the same as:
<%= render :partial => :belongs_to, :locals => { :parent => :employer, :form => form } %>
<div class="field span-16">
<div class="span-8 labelRight">
<%= form.label parent %>
</div>
<div class="span-8 last">
<%= form.collection_select :"#{parent}_id", parent.to_s.capitalize.constantize.find(:all), :id, :name,
{ :prompt => "Select an #{parent.to_s.capitalize}..." },
{ :class => "automatixSelect" } %>
</div>
</div>

Resources