Using Rails Active Record enum types with Simple_Form
Asked Answered
C

9

18

I declare a model with an enum type like:

class Event < ActiveRecord::Base
    enum event_type: { "special_event" => 0,
                       "pto"           => 1,
                       "hospitality"   => 2,
                       "classroom"     => 3
                       }

Then in my update view, I have a form with:

<%= simple_form_for @event do |f| %>   
    <%= f.input :event_type, collection: Event.event_types.keys %>  
    ... 
<% end %>

This works great, and I get a select populated with my enumerated types. When I perform the @event.update(event_params) in my controller, I can check the db and see that the event_type field has been updated to the correct integer value.

However, when I revisit the edit page, the select shows a nil value. If I check its value by adding a debug line to my form:

<%= f.input :event_type, collection: Event.event_types.keys %>  
<%= debug @event %>

I see that the value for event_type is correct:

--- !ruby/object:Event
attributes:
  ...
  event_type: '2'

but the input selector is still blank rather than showing "hospitality" as it should.

Any ideas would be greatly appreciated. :)

Careful answered 14/8, 2014 at 21:4 Comment(0)
H
27

this line worked just fine. <%= f.input :event_type, collection: Event.event_types %>

Do you have to manually set the selected value ? what's your version of simple_form ?

Heedful answered 9/10, 2014 at 11:40 Comment(2)
This works fine if you're OK with the default Simple Form labels as your enum names. If you want to provide display names, you'd need to use the Simple Form i18n functionality, and be sure to pass the enum keys as symbols not strings. Something like Event.event_types.symbolize_keys.keys. Not the most ideal, IMO.Triviality
Thanks for the tip, I did this ``` = f.input :category, collection: Demographic.categories.keys, label_method: :titleize ```Kentigerma
C
13

Vincent's solution gives me the error: '0' is not a valid 'fieldname'

I had to add keys as suggested in other stackoverflow post: <%= f.input :event_type, collection: Event.event_types.keys %>

Cordilleras answered 5/4, 2018 at 21:53 Comment(0)
U
8

Use the enum_help gem. Lets you do this:

<%= f.input :event_type %>
Uncovered answered 24/12, 2014 at 11:20 Comment(0)
M
8

I got stuck on this one too. I needed to titlieze my enums so they wouldn't look so wonky with the snake_case that I was using. I used to_a to take the ruby hash and turn it into an array and then I used collect to return a new array in the format that I needed.

collection: Event.event_type.to_a.collect{|c| [c[0].titleize, c[0]]}

Hopefully this will help someone else out.

Moten answered 18/4, 2018 at 3:48 Comment(0)
G
2

For example, assuming you have an enum like this one in your model (Model Role in the example):

enum :work_type, in_person: "in_person", remote: "remote", hybrid: "hybrid"

This will work in your view

= f.input :work_type, as: :select, collection: Role.work_types.collect { |key, value| [key.to_s.titleize, value] }

This will out put the following HTML:

<select class="form__input" name="role[work_type]" id="role_work_type">
  <option selected="selected" value="in_person">In Person</option>
  <option value="remote">Remote</option>
  <option value="hybrid">Hybrid</option>
</select>
Galen answered 9/6, 2022 at 16:38 Comment(0)
C
0

Thanks for following this up. I believe the issue I reported was caused by an incorrect declaration for event_type. In my migration, I had accidentally defined event_type as String rather than an Integer:

class CreateEvents < ActiveRecord::Migration
  def change
    create_table :events do |t|
      ...
      t.string :event_type
      ...
    end
  end
end

I believe that enum's should be declared as integers to work correctly. Unfortunately, I did not test that changing the type to integer makes it work because I actually ended up using a different approach. Rather than using an enum I instead defined my collection of event types in my model:

class Event < ActiveRecord::Base
  def self.types
    ['Special_Events', "On-Going", 'PTO', "Classroom"]
  end
  ...
end

And, then in my form, used simple form with this syntax:

<%= f.input :event_type, collection: Event.types, input_html: { autocomplete: 'off' }  %>

And all worked well.

Careful answered 10/10, 2014 at 15:15 Comment(0)
C
0

I'm using draper as decorator, so I'd like to add words translation into model's decorator. Here is my code:

app/decorators/meter_decorator.rb

class MeterDecorator < Draper::Decorator
  delegate_all

  STATUS_MAPPING = {
    uninitialized: '未安装',
    good: '良好',
    broken: '故障',
    disabled: '禁止'
  }

  def status
    STATUS_MAPPING[object.status.to_sym]
  end
end

views/meters/_form.html.erb

<%= f.input :status, collection: MeterDecorator::STATUS_MAPPING, label_method: :last, value_method: :first, include_blank: false %>

views/meters/index.html.erb

<td><%= meter.decorate.status %></td>
Caslon answered 12/6, 2016 at 8:19 Comment(0)
M
0

<%= f.input :event_type, collection: Event.event_types.transform_keys(&:titleize) %>

Just passing the enum hash as it is would be enough. but if you want to alter the options you can use transform_keys

Marinemarinelli answered 15/7, 2024 at 11:22 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Noreennorene
C
-1

With some more research, I came up with the following solution:

<%= f.input :event_type, collection: Event.event_types.keys,
            :selected => Event.event_types.keys[@event[:event_type].to_i], 
            input_html: { autocomplete: 'off' }  %>

So, I had to do 2 things:

  • Use :selected to set the value of the selector. This required the cumbersome syntax Event.event_types.keys[@event[:event_type].to_i] to set the select value. I'd love to hear if there is a simpler syntax I could have used. :)
  • Set autocomplete: 'off' to prevent firefox from wanting to set the selector to its previous setting on a page reload.

Alternate, simpler solutions would be welcomed!

Careful answered 14/8, 2014 at 23:33 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.