I'm trying to make an app in Rails 4.
I've recently asked these 2 questions, and taken the advice in the responses. Rails 4 - how to use enum?
I'm still struggling.
I have a form with an input selector:
<%= f.input :self_governance, as: :select, label: "Select your governance approach", collection: Preference.self_governances.to_a.map { |p| [p.to_s.humanize, p] } %>
When I save this and try it, the select menu shows:
["tier_1", 1]
What I want is to display: Tier 1
At the moment, I have a preference model with:
enum self_governance: {
tier_1: 1,
tier_2: 2,
tier_3: 3,
tier_4: 4,
tier_5: 5
}
enum autonomy: {
tier_11: 1,
tier_21: 2,
tier_31: 3,
tier_41: 4,
tier_51: 5
}
I have a preferences show view:
<%= #organisation.preference.self_governance.try(:humanize) %>
Also, when I accept the form problem (for now) and try to render the show page, I get this error:
'["tier_1", 1]' is not a valid self_governance
Can anyone see what I've done wrong?
I just want to save the number 1 in the database, but display the words 'Tier 1'.
Update your form to properly return a collection of keys and values from your enum. Preference.self_governances is a type of hash object.r Rather than call to_a, just iterate over the keys and values:
<%= f.input :self_governance, as: :select, label: "Select your governance approach", collection: Preference.self_governances.map { |key, val| [key.humanize, key] } } %>
If we look at just the output of:
Preference.self_governances.map { |key, val| [key.humanize, key] }
We get the following:
[
["Tier 1", "tier_1"],
["Tier 2", "tier_2"]
...
]
Note that the first value is what gets shown as the select label and the second value is what gets sent to your controller within the param.
EDIT:
When using an enum, you can assign either the key or value of the enum to the field.
preference.self_governance = 1 # Works
preference.self_governance = :tier_1 # Works
preference.self_governance = "tier_1" # Works
But you can't assign the value as a string:
preference.self_governance = '1'
=> "ArgumentError: '1' is not a valid self_governance" # Doesn't work, tries to look for key '1' in enum, but doesn't exist.
So make sure you pass the key of the selected enum (i.e. "tier_1") aback to your form or else you ma
Related
I want to send a different value to the server than what the text representation of the value is for a select field. All of my attempts at this seem to fail. Here is what I'm currently working with.
<td><%= f.select :code, ["BOB"], { value: "STEVE" }, { class: "account-rep-code", "data-user-codes" => current_user.code_list } %></td>
On submit of this example, I want to send "STEVE" to the server not "BOB". But "BOB" keeps sending anyway. How can I adjust this so that "STEVE" sends to the server as the value of the field?
The ActionView/Helpers/FormBuilder#select is defined as:
select(method, choices = nil, options = {}, html_options = {}, &block)
Where the choices parameter is an array of arrays, and the first value in each of them corresponds to the option "inner html", and the second one, to the option value. So in your case you could add [%w[BOB STEVE]] and this would give you an option like:
<option value="STEVE">BOB</option>
So
<%= form.select :name, [%w[BOB STEVE]], ... %>
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] }
I'm trying to make an app on Rails 4.
I posted this question and got some advice: Rails 4 -Simple Form how to save key and display value
I am trying to figure out how to implement this advice.
At the moment, I have a preference model with:
enum self_governance: {
tier_1: 1,
tier_2: 2,
tier_3: 3,
tier_4: 4,
tier_5: 5
}
enum autonomy: {
tier_11: 1,
tier_21: 2,
tier_31: 3,
tier_41: 4,
tier_51: 5
}
In my preference form, I have:
<%= f.input :self_governance, as: :select, label: "Select your governance approach", collection: Preference.self_governance.to_a.map { |p| [p.humanize, p] } %>
I have a preferences show view:
<%= #organisation.preference.self_governance.try(:humanize) %>
When I save all this and try it, I get this error:
NoMethodError at /preferences/1/edit
undefined method `self_governance' for #<Class:0x007fde5b9fb500>
Did you mean? self_governances
Can anyone see how to make this work?
Do I maybe need to add def/end tags to the enum in the preference model? I don't have any experience with using the code 'enum'
You're so close :) The fix is right in the error.
Your select is calling
Preference.self_governance.to_a.map { |p| [p.humanize, p] }
And your error tells you the pluralization is wrong. Remember that if you call enum on a single object, it will be
#preference.self_governance
But if you call on the model itself, Preference, and request a collection it's plural.
Preference.self_governances
Because enum is special, uour enum's could just be arrays, instead of hashes:
enum self_governance: [ tier_1, tier_2, tier_3, tier_4, tier_55 ]
enum autonomy: [ tier_11, tier_21, tier_31, tier_41, tier_51 ]
Your view would look like:
<%= f.input :self_governance, as: :select, label: "Select your governance approach", collection: Preference.self_governances.map { |key, value| [key.humanize, key] } %>
It will store the index number of the array, like magic :)
Rails pluralizes the enum collection for you, so yours could be self_governances, for instance.
What that means is that Preference.self_governances would return the hash with the definitions and the attribute that actually holds the value is the one in singular like #preference.self_governance
An example:
#preference = Preference.new
#preference.self_governance = Preference.self_governances[:tier_1]
When you use enum what rails will do internally is add a pluralized class method definition with the name that you defined that will return a hash with the values and, will use the name that you defined, as it was written by you, for an attribute accessor that will either get/set the actual value of the enumeration on instances of your object.
Another, common use is for status, given a Test class:
enum status: {
active: 1,
inactive: 2
}
So for the above sample rails would add a Test.statuses methods that simply returns the values of your enum. Then, for an instance of a Test object you would have an accessor #instance.status with the name of your name which you can use to get or set a status from the hash returned by Test.statuses
Hopefully it makes sense.
I'm running Rails 4 on Ruby 2.0
I'm trying to populate a select tag with a key value pair array I have setup in my model. However, I am having trouble figuring out how to grab the key. Here is what I have so far:
Model
class Store
Colors = ['blue', 'green', 'red', 'yellow', 'orange', 'pink', 'purple', 'lime', 'magenta', 'teal']
SearchParams = {'isbn' => 'ISBN', 'intitle' => 'Title', 'inauthor' => 'Author', 'inpublisher' => 'Publisher', 'subject' => 'Subject', 'lccn' => 'LCCN', 'oclc' => 'OCLC'}
end
Controller
def index
#search_params = Store::SearchParams.map { |param| [param, param.key] }
end
note: I am aware that .key does not exist - I added that hoping it would better communicate what I am trying to do.
View
<%= form_tag do %>
<%= select_tag :param_name, #search_params, prompt: 'choose' %>
<% end %>
I would like the value of each <option> to be the key, and for the user to see the value. I hope that makes sense.
You generally use options_for_select to provide the options for select_tag. Conveniently, you can hand a Hash to options_for_select and it will do the right thing:
options_for_select(container, selected = nil)
Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. [...]
The problem is that options_for_select wants the Hash's keys to be what the human sees and the values to be the value attributes for the <option>s. Your Hash is backwards but you can use Hash#invert to flip the keys and values around:
invert → new_hash
Returns a new hash created by using hsh’s values as keys, and the keys as values.
So you could just do this in your controller:
#search_params = Store::SearchParams.invert
and then this in the ERB:
<%= select_tag :param_name, options_for_select(#search_params), prompt: 'choose' %>
I think, this itself will work
def index
#search_params = Store::SearchParams.to_a
//it will return the array you want, but the values will be [[key1,value1],[key2,value2]]
// if you want to reverse itm then Store::SearchParams.to_a.collect{|arr| arr.reverse} will give that
end
That will do it:
def index
#search_params = Store::SearchParams.map { |key, val| [val, key] }
end
UPD: consider also Hash#invert (thanks to #mu is too short)
I have such form partial for CRUD actions:
= form_for #vehicle do |f|
= f.select :fuel_type, [["Выбрать", "None"], "Бензин", "Дизель", "Газ", "Гибрид", "Электричество", "Другое"], {:required => true, :selected => #vehicle.fuel_type}
So as you can see in db i store hole word, as for example Бензин or Дизель etc...
But when i try to edit using my form partial some data, i see that as default selected value of my selectbox is None (displayed as Выбрать). But when in db that field is Бензин why it is set to None in form view? How to see Бензин?
Also note that for new action #vehicle.fuel_type will be empty
I would pair the labels with a value, and store the value in the database as an integer:
[['Бензин', 1], ['Дизель', 2], ['Газ', 3]]
You can include blank on your collection to select none:
f.select :fuel_type, [['Бензин', 1], ['Дизель', 2], ['Газ', 3], ...], { :include_blank => "Выбрать" }
In this way you won't need :selected => #vehicle.fuel_type on your edit form as the value will be populated from the model if selected.
There is probably a better way to handle it and this functionality could also be done in the model, but to display the saved value you could create a helper method:
def map_fuel_type(value)
case value
when 1
'Бензин'
when 2
'Дизель'
when 3
'Газ'
when 4
'Гибрид'
when 5
'Электричество'
when 6
'Другое'
end
end
And then to show the value on your index or show page:
<%= map_fuel_type #vehicle.fuel_type %>
To store as string:
f.select :fuel_type, ["Бензин", "Дизель", "Газ", "Гибрид", "Электричество", "Другое"], { :include_blank => "Выбрать" }