rails form for model select box with 1-dimensional data - ruby-on-rails

I want to limit the entry possibilities for a text field in my model to a previously defined array.
How do I make an options_for_select with just a 1-dimensional array like ["foo","bar","foobar"]?
I tried
form_for #mappings do |f|
f.select(:mapping_type, options_for_select(["foo","bar","foobar"]), class: "..."
end
But the select box comes out all messed up like this:
<select name="section_mapping[mapping_type]" id="section_mapping_mapping_type">
as opposed to what it should be:
<select name="mapping_type" >
EDIT:
I changed the f.select to select_tag and the form shows up without any errors but when I submit it, it leaves that field empty
EDIT 2:
f.collection_select(:mapping_type, options_for_select([...]), class: "..."
works as in it submits the form with the value correctly, but the HTML class is not applied. Why is that?

Basically, you want to be able to tie your collection select to a property of the object (in your case, #mappings)
Also, from the doc on rails collection_select, it will take options as follow:
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {}) public
Objet: the object you are binding the selected option to (#mappings [f]) in this case
method: The property/attribute of the object (in this case, mapping_type)
collection: The collection for select ( ["foo","bar","foobar"] )
value_method: The value you want to send back with the submit (Note that this is a method which means you should be able to call it on an object.) more on this later.
text_method: The value you want to show as text on the select option on the view (this is also a method as above, more on this later as well)
options: any additional option you want, (e.g: include_blank)
html_options: eg: id, class etc.
As concerning the value_method and text_method, these are methods that should be called on your collection, which means that your collection will be an array of objects.
To this end, you can have the following:
class CollectionArr
include ActiveModel::Model
attr_accessor :name
ARR = [
{"name" => "foo"},
{"name" => "bar"},
{"name" => "foobar"}
]
def self.get_collection
ARR.collect do |hash|
self.new(
name: hash['name']
)
end
end
end
From here, calling CollectionArr.get_collection will return an array of objects where you can cal .name to return either foo, bar, or foobar. This makes using the collection_select and easy deal from here:
<%= f.collection_select : mapping_type, CollectionArr.get_collection, :name, :name, {:include_blank => "Select one"} %>
And all is green...

Related

How do you make a rails multi select dropdown work

I am trying to make a multi select dropdown work with a dialog for search parameters. I can make the dropdown multi select but can't seem to get/pass the resulting data. (edited/new info will be in italics)
I believe that the root of the problem is that I need to change the permit section in my controller to reflect that I am passing a hash/array. If I look at the resulting record, the 2 fields that I am setting as multi-selects show as nil. However, if I force an errror, the parameters shown by rails show the correct choices. therefore, I believe that the problem might be with the permit section.
That looks like
*def search_params
params.require(:search).permit(:document_title,
:summary,
:owner,
:category,
:file_name,
:doc_to_email,
:categories_attributes => [:name])
end*
I added the :categories_attributes => [:name] to try to get the controller to allow hashes but that didn't work.
The select field is
<%= f.select :category[], options_for_select(#categories.sort), {:include_blank => true}, {:multiple => true, :size =>10} %>
but that gives me
.erb where line #41 raised:
wrong number of arguments (0 for 1..2) Trace of template inclusion:
app/views/searches/new.html.erb
I thought I had to set category as an array with the [] but obviously I'm missing something.
Category is a string field in the Searches table.
You do not need the [] brackets after the field name as Rails adds those in automatically.
See the example here:
http://apidock.com/rails/ActionView/Helpers/FormTagHelper/select_tag
select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>".html_safe, multiple: true
# => <select id="colors" multiple="multiple" name="colors[]"><option>Red</option>
# <option>Green</option><option>Blue</option></select>
In your case the selected values will be available as an array in params[:search][:category] after the form is submitted.
If you use strong parameters, also make sure you have :category => [] in the permit list.

How do I properly use a select box with ruby on rails?

I have a select box for the event types of an event. event belongs to event_type and event_type has many events. Here's what I have for the select box:
<%= f.select :event_type, options_from_collection_for_select(EventType.all, :id, :name, #event.id), :placeholder => 'Select an event type' %>
But, the problem is that when I submit it, it submits the id of the event type and not the name of it. So, how would I make it submit the name rather than the id? If you need to see the any more code than just tell me, thanks
The second parameter to options_from_collection_for_select is the value that will be submitted with the form. You have :id, so change it to :name.
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_from_collection_for_select
(but this seems like a strange thing to do - typically you would store the event type ID.)
You can use the id after the submit to load the event type again in your controller post action like this:
selected_type = EventType.find(params[:event_type]
It is also a good practice to keep database calls to the controller, so please put the EventType.all statement in there and pass it as local or class variable like you did with event.
If you really want to pass the name in your form instead of the id, you can replace the :id part in your call to something more like this options_from_collection_for_select(#event_types, :name, :name, #event.event_type.name). Keep in mind that this value should be unique!
The method works like this:
options_from_collection_for_select(collection, value_method, text_method, selected = nil)
So the first parameter contains all the options, the second defines the value within those option objects which are put into the value field of the HTML option (which is being submitted by the form), the third defines the text which is displayed to the user and the final parameter defines the value of the selected entry (in case you are editing an entry for example). For the last parameter, you need to use the events' event_type id, or in your case, the name because you set the value of your HTML tag to it.
Use pages like ApiDock or the Rails tutorials to get examples for some of these methods.
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_from_collection_for_select
You should pass name in the Value method, if you want to pass the name,
<%= f.select :event_type, options_from_collection_for_select(EventType.all, :name, :name, #event.id), :placeholder => 'Select an event type' %>
Here is the doc for options_from_collection_for_select

ruby on rails how to use FormOptionHelpers to create dynamic drop down list

I have checked some tutorials but I got confused by the parameters in this method
collection_select (object, attribute, collection, value_method, text_method, options = {}, html_options ={})
I have a map model includes: :area, :system, :file
and I want to read :area from database to a drop down list, and let user choose one
I already did #map = Map.all in the view
what the method should be?
especially the parameter "attribute". In a lot tutorials, people put "id" here. But I don't know what "id" is, and in my situation I don't need any other value, just the "area".
Im not exactly sure what you are asking here but if you are trying to make a dropdown selection for use in an html form will this example help you at all?
<% nations = {'United States of America' => 'USA', 'Canada' => 'Canada', 'Mexico' => 'Mexico', 'United Kingdom'=> 'UK'} %>
<% list = nations.sort %>
<%= f.select :country, list, %>
Here nations is a hash of countries then list becomes the sorted copy of that hash. An html dropdown is then created as a part of the form "f". ":country" is the part of the model that the data is connected to while list is the options to populate the dropdown with
It's not clear from your question what the model is that's being populated with the area.
Typically, collection_select is used between related models.
eg.
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belongs_to :category
end
When selecting the 'category' for a product, your view would have something like:
<%= f.collection_select(:category_id, :id, Category.all, :name, include_blank: true) %>
What this does is specify the Product.category_id as the attribute being populated with the value of Category.id. The values come from the Category.all collection, and with Category.name being the item displayed in the select. The last (optional) parameter says to include a blank entry.
Something like the following is probably what you need:
<%= f.collection_select(:map_id, :id, #map, :area) %>
However, if the model you're trying to populate has an area attribute (instead of an ID linking to the map), you might need to use:
<%= f.collection_select(:area, :area, #map, :area) %>
This specifies that the area attribute of the receiving table will be populated with Map's area attribute, which is also being used as the "description" in the select.

Rails store key value for a select input

I have in my .html.erb:
<label for="form_marital_status">Marital Status:</label>
<%= select("form", "marital_status", marital_status_options, {}, { }) %>
Where marital_status_options is defined in my helper as:
def marital_status_options
%w[Select Single Married Common-Law/Partner Divorced Widowed]
end
Is there a way I can define marital_status_options to have a key value pairing for use in the select?
%w[Select Single Married Common-Law/Partner Divorced Widowed]
This is going to make the option value and text for each option the same. Return an array of arrays if you want the option value and text to be different for each option. The first value in each array is the text value for the option; the second is the option value itself.
def marital_status_options
[["Select", ""], ["Single", "single"], ["Married", "married"], ["Common-Law/Partner", "partners"], ["Divorced", "divorced"], ["Widowed", "widowed"]]
end
This is explained clearly in the documentation.
You should also consider not passing the blank "Select" option from your method as there is a way to do this through the select method itself.
# Helper
def marital_status_options
[["Single", "single"], ["Married", "married"], ["Common-Law/Partner", "partners"], ["Divorced", "divorced"], ["Widowed", "widowed"]]
end
# form
<%= select("form", "marital_status", marital_status_options, {:include_blank => "Select"}) %>

Can someone explain collection_select to me in clear, simple terms?

I am going through the Rails API docs for collection_select and they are god-awful.
The heading is this:
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
And this is the only sample code they give:
collection_select(:post, :author_id, Author.all, :id, :name_with_initial, :prompt => true)
Can someone explain, using a simple association (say a User has_many Plans, and a Plan belongs to a User), what I want to use in the syntax and why?
Edit 1: Also, it would be awesome if you explained how it works inside a form_helper or a regular form. Imagine you are explaining this to a web developer that understands web development, but is 'relatively new' to Rails. How would you explain it?
collection_select(
:post, # field namespace
:author_id, # field name
# result of these two params will be: <select name="post[author_id]">...
# then you should specify some collection or array of rows.
# It can be Author.where(..).order(..) or something like that.
# In your example it is:
Author.all,
# then you should specify methods for generating options
:id, # this is name of method that will be called for every row, result will be set as key
:name_with_initial, # this is name of method that will be called for every row, result will be set as value
# as a result, every option will be generated by the following rule:
# <option value=#{author.id}>#{author.name_with_initial}</option>
# 'author' is an element in the collection or array
:prompt => true # then you can specify some params. You can find them in the docs.
)
Or your example can be represented as the following code:
<select name="post[author_id]">
<% Author.all.each do |author| %>
<option value="<%= author.id %>"><%= author.name_with_initial %></option>
<% end %>
</select>
This isn't documented in the FormBuilder, but in the FormOptionsHelper
I've spent quite some time on the permutations of the select tags myself.
collection_select builds a select tag from a collection of objects. Keeping this in mind,
object : Name of the object. This is used to generate the name of the tag, and is used to generate the selected value. This can be an actual object, or a symbol - in the latter case, the instance variable of that name is looked for in the binding of the ActionController (that is, :post looks for an instance var called #post in your controller.)
method : Name of the method. This is used to generate the name of the tag.. In other words, the attribute of the object you are trying to get from the select
collection : The collection of objects
value_method : For each object in the collection, this method is used for value
text_method : For each object in the collection, this method is used for display text
Optional Parameters:
options : Options that you can pass. These are documented here, under the heading Options.
html_options : Whatever is passed here, is simply added to the generated html tag. If you want to supply a class, id, or any other attribute, it goes here.
Your association could be written as:
collection_select(:user, :plan_ids, Plan.all, :id, :name, {:prompt => true, :multiple=>true })
With regards to using form_for, again in very simple terms, for all tags that come within the form_for, eg. f.text_field, you dont need to supply the first (object) parameter. This is taken from the form_for syntax.

Resources