2

Is it hacky to manually list my form options as strings within the select_tag helper?

Also, I'm wondering--how do I actually use the selected value to update the database?

  <div class="form-group">
    <%= f.label :sex %><br />
    <%= select_tag(:sex_id, options_for_select(
      [
        ["Not known", 0], ["Male", 1], ["Female", 2], ["Not applicable", 3]
      ]
    )) %>
Michael P.
  • 1,373
  • 3
  • 12
  • 33

2 Answers2

2

This question outlines the process of using enum in ActiveRecord (Rails 4.1+) for mapping to integers.

An attribute of type integer in the database can be declared in corresponding model (I assume User):

enum gender: [:not_known, :male, :female, :not_applicable]

In view, you may rely on the fact that the system wants corresponding strings, not integers:

<%= f.input :gender, as: :select, collection: User.genders.keys %>

Or map them yourself to generate what you want: "human-readable names" or even i18n keys:

<%= f.input :gender, as: :select,
      collection: User.genders.keys.map { |w| [w.humanize, w] } %>
<%= f.input :gender, as: :select,
      collection: User.genders.keys.map { |w| [(t ".w"), w] } %>
Community
  • 1
  • 1
D-side
  • 9,150
  • 3
  • 28
  • 44
  • All right. I'm a novice here and am struggling to understand what you've written just a little. Firstly, where does your first code sample go? In the user model? In the sex model? And how does this relate to ActiveRecord? Is there a resource that I could read or watch that would break this down for me a bit more? – Michael P. Dec 16 '14 at 06:43
  • First code sample goes to whichever model has this attribute. As for the docs -- will add a link in a moment. – D-side Dec 16 '14 at 06:44
1

The way you're hardcoding the options into the view will tend to make lookups difficult and localization/internationalization impossible.

There are many ways to do it better. Here are ones for you to consider.

Use a module that provides an enumeration, such as:

module Gender
  UNKNOWN = 0
  MALE = 1
  ...

Use a constant hash lookup, such as:

GENDER = {
  0 => "Not Known",
  1 => "Male",
  ...

Use a constant array where the index is the id, such as:

GENDER = [
 "Not Known",
 "Male",
  ...

Use a an array of structures, such as attribute key-value pairs:

GENDER = [
  {id: 0, label: "Not Known"},
  {id: 1, label: "Male"},
  ...

Use a database table, such as:

class Gender < ActiveRecord::Base
   # has fields for id and name
end

Use Rails 4.1 enum:

class User < ActiveRecord::Base
  enum gender: [ :unknown, :male, ... ]
  ...

Each of these options has strengths.

  • In general I suggest using the database table approach for a typical web app, or typical API; the table approach has many advantages for easier scoping, searching, sorting, automatic display using admin tooling, etc.

  • In general I suggest using the module approach if you need high speed, or have very tight storage constraints, or want to keep localizaiton/internationalization strings elsewhere such as a YAML file; the module approach stores the smallest amount of information necessary.

For sex and gender, heads up that these vary by region and userbase. For instance, some countries have a third gender, some contexts require a "Decline to answer", some groups distinguish between sex and gender, etc.

joelparkerhenderson
  • 34,808
  • 19
  • 98
  • 119