Update: This StackOverflow answer provides a better way to use a drop-down with enums. I could’ve sworn I tried that, but maybe not.
I discovered something interesting about the way ActiveRecord 4.1 enums work. If you’re trying to use them with options_for_select, you may need to do some little acrobatics with your enums.
Assume your model provides:
class Car < ActiveRecord::Base
# body_style is an integer in the database
enum body_style: [:coupe, :convertible, :van, :suv, :sedan]
end
And your update route for cars_controller
does this:
class CarsController < ApplicationController
before_action :set_car, only: [:show, :edit, :update, :destroy]
# PATCH/PUT /cars/1
# PATCH/PUT /cars/1.json
def update
respond_to do |format|
if @car.update(car_params)
format.html { redirect_to @car, notice: 'Car was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: @car.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_car
@car = Car.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def car_params
params.require(:car).permit(:body_style)
end
end
Then, using the enumeration in a form_for block in your view requires a deviation from what Car.body_styles
will give you.
The value submitted by this form snippet won’t validate because update is expecting the “string” key, and not the underlying numerical value of the table.
<%= form_for(@car) do |f| %>
<%= f.label :body_style %>
<%= f.select :body_style, options_for_select(Car.body_styles) %>
Instead, a little bit of transformation needs to be done so that the description/value pair for the elements are both the text value of the enum.
<%= form_for(@car) do |f| %>
<%= f.label :body_style %>
<%= f.select :body_style, options_for_select(Car.body_styles.map {|k,v| [k,v]}) %>
Or, with the selected value included:
<%= form_for(@car) do |f| %>
<%= f.label :body_style %>
<%= f.select :body_style, options_for_select(Car.body_styles.map {|k,v| [k,v]}, @car.body_style) %>