simple_form_for custom label_for - ruby-on-rails

I've a select that has to provide some decimal values (percentages) for an accounting application.
The values are like 10, 20, 22.5.
The problem is that want to display the first two values with no decimal part, the third with it.
In the simple_form_for documentation, in the Collections section, it talks about a label_method, and i guess it would solve the problem.
Can you provide an example of usage of such a method?
It would be enough, but for clarity my simple_form_for is something like this :
<%= simple_form_for(#company) do |f| %>
...
<%= f.input :percentage, :collection=>[BigDecimal(10),BigDecimal(20),BigDecimal(22.5,3)]%><br />
...
And here is what i get:

Summarized, label_method allows you to define a method, which is called for each of the items in the given collection, and of which the result is used to display the item
Either you give a symbol as label method, like
label_method: :method_to_be_called
or you define the method in place, like
label_method: lambda { |value| calculated_label }
In your case, I would define the collection as
[ [BigDecimal(10), 0], [BigDecimal(20), 0], [BigDecimal(22.5, 3), 2] ]
and the label_method as
label_method: lambda { |value| number_with_precision(value[0], precision: value[1]) }
You probably also need a value_method, returning the right result to your server, something like
value_method: lambda { |value| value[0] }

Related

Rails 4 -Simple Form how to save key and display value

I'm trying to make an app in Rails 4. I use simple form for forms.
I have an attribute called 'self_governance' in my model.
I've written a helper method so that I can define 5 levels which can be stored for this attribute, but which are displayed to the user as options (rather than numbers 1 .. 5).
In my helper, I have:
module PreferencesHelper
def self_gov_selector
[
[ 'tier 1','1'],
[ 'tier 2','2'],
[ 'tier 3','3'],
[ 'tier 4','4'],
[ 'tier 5','5'],
]
end
In my form, I then have:
<%= f.input :self_governance, :label => "Select your tier", collection: self_gov_selector %>
Then in my show, I'm trying to figure out how to display 'tier 1' instead of '1'.
I have tried:
<%= #preference.self_governance %>
<%= #preference.self_gov_selector %>
I can't find anything that works. They all display 1 instead of Tier 1 in the views.
How can I make this work?
The params posted by the form will only include the second value in the array, so you're likely storing your value as an integer in your database table.
A simple solution is to use an enum to map the integers you're storing to the values they represent:
In your Preference model:
enum self_governance: {
tier_1: 1,
tier_2: 2,
tier_3: 3,
tier_4: 4,
tier_5: 5
}
Then update your view accordingly:
<%= #preference.self_governance.try(:humanize) %>
EDIT:
An additional bonus of this approach is that you can replace your helper method with calling the enum directly:
f.input :self_governance, as: :select, label: "your label", collection: Preference.self_governances.map { |key, val| [key.humanize, val] }

rails form for model select box with 1-dimensional data

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

Uniq value in option_from_collection_for_select

How i can print only unique value in options_from_collection_for_select() helper ?
Because i don't want to have 10 times the same value...
<%= select_tag :type, options_from_collection_for_select(
Course.where(category_id: #category.id),
:learning_type,
:learning_type,
#type)
%>
I'm not sure what you are trying to do here. Let's say you have Course model, and you want to show the uniq learning_type of the course. You can get the results as an array with something like:
Course.where(category_id: #category.id).pluck(:learning_type).uniq
or
Course.where(category_id: #category.id).pluck('DISTINCT learning_type')
It's always better to use Fat model and use scopes in your Course model thought.
Now you can easily use the array with that form helper, something like:
<%= select_tag :type, options_for_select(Course.where(category_id: #category.id).pluck('DISTINCT learning_type')) %>

Array as Parameter from Rails Select Helper

I'm working on a legacy project that is using acts_as_taggable_on which expects tags to come in arrays. I have a select box allowing users to select a tag on a Course in a field called categories. The only way mass assignment create will work is if params looks like this params = {:course => {:categories => ['Presentation']}}. I've currently a view with this helper:
<%= f.select 'categories', ['Presentation' , 'Round Table' , 'Demo', 'Hands-on'] %>
Which will give me a parameter like params = {:course => {:categories => 'Presentation'}}. This doesn't work since Acts as tag gable apparently can't handle being passed anything other than a collection.
I've tried changing categories to categories[] but then I get this error:
undefined method `categories[]' for #<Course:0x007f9d95c5b810>
Does anyone know the correct way to format my select tag to return an array to the controller? I'm using Rails 3.2.3
I didn't work with acts_as_taggable_on, but maybe this simple hack will be suitable for you? You should put it before mass-assignment.
category = params[:course][:categories]
params[:course][:categories] = [category]
If you are only going to allow the selection of ONE tag, you could do:
<%= f.select 'categories', [['Presentation'] , ['Round Table'] , ['Demo'], ['Hands-on']] %>
Each one item array will have first for the display value, and last for the return value, which in this case will both return the same thing, as the first element of the array is the same as the last element when the array as one element.
Seems like select doesn't give you that option.
If I understand correctly, one option might be to use a select_tag instead and just be explicit about where you want the selection in the params:
<%= select_tag 'course[categories][]', options_for_select(['Presentation' , 'Round Table' , 'Demo', 'Hands-on']) %>
That ought to get your params the way you need them.
Here's what I'm using for one of my projects:
<% options = { include_blank: true } %>
<% html_options = { required: true, name: "#{f.object_name}[#{resource.id}][days][]" } %>
<%= f.select :days, DAYS, options, html_options %>
Without html_options[:name], Rails handles the name of the select tag and spits out something like
service[service_add_ons_attributes][11][days]
but I need
service[service_add_ons_attributes][11][days][]
So I override it.
Hope that helps.

collection_select set option value of :include_blank to zero

In my rails app, i have a drop down box where i retrieve all groups from the Group table and display them using the collection_select tag.
When the user selects 'None', I want to pass '0' as option value.
Currently, an empty string is passed.
Is there a way to include option value = 0 for 'None'?
<%= f.collection_select :SUB_GROUP, Group.all, :Group_ID, :Group_ID, :include_blank => 'None' %>
Many many thanks for any suggestion provided
If you use options_for_select in combination with select_tag you can achieve that using this:
options_for_select(
[['None', '0']].concat(
Group.all.collect { |g| [g.group_id.to_s, g.group_id.to_s] }
)
)
In order to keep your views uncluttered, you might want to generalize and move this into a helper method with a reasonable name.

Resources