Create Arrays for multiple Languages - ruby-on-rails

I am searching for an easy way to create a select with multiple languages. Currently, I have used a HELPER to store an array with my SELECT options.
Helper
list = ["Book", "DVD", "Table", "Chair"]
CATEGORY = Hash[*list.collect { |v| [v, list.index(v)] }.flatten]
View
<%= f.select :category, options_for_select(ApplicationHelper::CATEGORY, selected: 0), { :class => "selectpicker" } %>
If there is a way to somehow use the LOCALE file this would be amazing too.

One solution would be to keep translations in the DB, You can search there are multiple gems available like language select
If you want to pull options from your translation YML files, I suggest options_for_select. All in all something like:
en.yml
en:
my_options:
0: "Book"
1: "DVD"
2: "Table"
3: "Chair"
View:
<%= f.select :category, options_for_select(t("my_options").invert, selected: 0), { :class => "selectpicker" } %>
Rails i18n gives you a hash if you translate a non-leaf key, like "my_options". You need the invert because options_for_select expects the text before the value, and a translation hash is the other way around.
You can explore more about it there are many way to do it this one is one of them and simple way.

Related

Multiple identical collection_select tags in a form in Rails

I have multiple identical collection selects inside a single form. I prefer this over a multiple select list for aesthetic and UX reasons. I have to use a terrible kludge to make everything work right, and I'm wondering if there is a more elegant way to do this:
From the view:
<% 3.times do |i| %>
<%= collection_select("selected_item_" + i.to_s.to_s, :name, #items, :name, :name, { :include_blank => true }, { id: "selected_item_" + i.to_s }) %>
<% end %>
From the controller:
ItemContainer = Struct.new(:name)
3.times do |i|
param = ('selected_item_' + i.to_s).to_sym
instance_variable = '#' + param_name
if params[param] && !params[param].empty?
#selected_items << params[param][:name]
instance_variable_set(instance_variable, ItemContainer.new(params[param][:name]))
end
end
#selected_channels.each.... # do what I need to with these selections
Most of these gymnastics are needed to ensure that the item is still selected if the page is refreshed. If there were some way to force collection select to use arrays, that would be the answer, but I couldn't make that work.
If I understang right you're looking for selegt_tag method (docs: http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-select_tag)
You can write something like this
select_tag "people[]", options_from_collection_for_select(#people, "id", "name")
select_tag "people[]", options_from_collection_for_select(#people, "id", "name")
and it youd output two selects for people, which would be sent as an array on submit.
if you use the [] naming in your collection_select calls then the params will send over the data as an array
I am a bit confused as to the usage of collection_select here as it doesn't seem like you are using a model object? this example using select_tag - might be able to come up with something more appropriate to your issue if the model structures were known
# run this in the loop
# set selected_value to appropriate value if needed to pre-populate the form
<%= select_tag('name[]',
options_from_collection_for_select(#items, 'name', 'name', selected_value),
{ include_blank: true }
)
%>
in controller update/create action
# this works because the select tag 'name' is named with [] suffix
# but you have to ensure it is set to empty array if none are passed, usually only issue with checkboxes
names = params[:name] || []
names.each do |name|
puts name
end
side note: you can use string interpolation with ruby double quotes in places of + for string concatenation
<%= collection_select("selected_item_#{i}",
:name,
#items,
:name,
:name,
{ include_blank: true },
{ id: "selected_item_#{i}" }
)
%>
see also: http://apidock.com/rails/v3.2.13/ActionView/Helpers/FormOptionsHelper/options_from_collection_for_select

Can collection_select be used against yaml files?

My Rails application currently uses collection_select to select lookup values for drop downs etc. This has two advantages:
The values are consistent
The id of the selected value is stored in the database, not the text value
For example:
edit.html.erb
<div class="field">
<%= f.label :course_type %><br />
<%= f.collection_select :course_type, Lookup.find(:all,:conditions => ["model_name = 'course' and field_name = 'course_type'"]), :id, :lookup_text, include_blank: false,:prompt => "Course Type" %>
</div>
course_controller.rb
private
def get_lookups
#course = Course.find(params[:id])
#course_type = Lookup.find(#course.course_type).lookup_text
show.html.erb
<b>Course type:</b>
<%= #course_type %>
My application will be multi-lingual, and Rails handles this by using locale files.
The question is: Is it possible (and sensible) to populate lookup values from yml files, rather than model/tables, and can this be easily extended to handle multiple languages? How could the above code be replaced with yml-based code?
One solution would be to keep translations in the DB, perhaps with our Traco lib. I suspect it would work with collection_select.
If you want to pull options from your translation YML files, I suggest options_for_select. All in all something like:
en.yml
en:
my_options:
one: "Option 1"
two: "Option 2"
View:
select_tag :foo, options_for_select(t("my_options").invert)
Rails i18n gives you a hash if you translate a non-leaf key, like "my_options". You need the invert because options_for_select expects the text before the value, and a translation hash is the other way around.
To translate your collection_select, you simply create a new model method (let's say, "name_translated") which returns your translation from the YAML file:
View:
<%= f.collection_select :product_id, Product.all, :id, :name_translated %>
Model:
class Product < ActiveRecord::Base
def name_translated
I18n.t(name)
end
end
YAML file:
en:
name1: "Hammer"
name2: "Plastic sheets"
name3: "Duct tape"
I use select:
<%= f.select :role, MAIN_CONFIG['manager_roles'].map { |s| [s.last, s.first] }, selected: #manager.role %>
And my yaml file main_config.yml:
manager_roles:
admin: 'Суперадмин'
partner_admin: 'Администратор'
manager: 'Менеджер'

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.

Why does my select box display things backwards in rails?

I have the following view code:
<%= f.select :day_of_play, Team::DAYS_OF_WEEK %>
And I have to create the following map for it to work and display a select box:
DAYS_OF_WEEK = {"Sunday" => 0,
"Monday"=> 1,
"Tuesday"=> 2,
"Wednesday"=>3,
"Thursday"=>4,
"Friday"=> 5,
"Saturday"=>6,
}
I store the integer in the database, but then when I display the integer it seems backwards that I have to create another map in order to go from integer->to->Saturday?
What am I doing wrong and how should I implement this correctly, soit is the dry principle?
If you want to adhere to the DRY principle, I recommend using Date::DAYNAMES.
E.g. like this:
<%= f.select :day_of_play, Date::DAYNAMES.each_with_index.collect { |day,i| [day,i] } %>

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