Select enum from form to set role

房东的猫 提交于 2019-12-02 19:27:10

To start, enum is not the name of an attribute. The name of the attribute is role.

Take a look at the rails-devise-pundit example application, specifically the file app/views/users/_user.html.erb which is a partial that creates a form to allow the administrator to change a user's role. I doubt you want to use a collection_select for helper (that is suitable if you have a separate Role model). Instead, an ordinary select form helper will work.

Here's a simple example that hardcodes the role options:

<%= f.select(:role, [['User', 'user'], ['Vip', 'vip'], ['Admin', 'admin']]) %>

Here is a better example that avoids hardcoding the roles in the form:

<%= f.select(:role, User.roles.keys.map {|role| [role.titleize,role]}) %>

The statement obtains an array of roles from the User model and constructs an array of key-value pairs using the map method.

Since you are using Rails 4 or higher, enums are even less complicated.

Given the following enum:

enum role: {
  admin: 1
}

Enums expect the HTML option attribute value to be the enum key:

<option value="admin"> <!-- As opposed to: <option value="1"> -->

Knowing this, you can pass in the enum keys.

<%= f.select :role, User.roles.keys, {}, class: 'user-roles-select' %>

Then using CSS you can modify the appearance.

.user-roles-select option {
  text-transform: capitalize;
}

The cleanest way that I've come with in order to use collection_select with enums is the following:

f.collection_select :diet_preference, User.roles.map{ |dp| [dp.first, dp.first.humanize] }, :first, :second

Here is how I did it, with internationalization and ordering, and auto select the current_user role if already defined. It assumes that you have a locale file with a roles: category containing all your enum roles such as :

# your locale file
en:
 roles:
  admin: "Administrator"
  mode: "Moderator"


# model user.rb
enum role: { admin: 0, mode: 1 }
ROLES = User.roles.map { |r,| [I18n.t("roles.#{r}"), r] }.sort_by { |r| I18n.t("roles.#{r}") }

# view

<%= f.select :role, User::ROLES, { prompt: t("users.roles.prompt"), selected: @user.role }, { class: "form-control" } %>

As enum is a wrapper for integer in Rails, and I wanted to store strings in DB instead, I did the following:

    class Child < ApplicationRecord
       enum year: {
          Infant: 'Infant',
          '2-5_years': '2_to_5_years',
          '5-8_years': '5_to_8_years',
          '8-10_years': '8_to_10 years',
          'More_than_10_years': 'More_than_10_years'
       }
       AGE_YEARS = Child.years.map { |k, v| [k.humanize, v] }
     }

In my form,

<%= f.select :age, options_for_select(Child::AGE_YEARS, params[:age]), include_blank: 'Select an age-group.' %>

As I was using PostGREsql server wherein a pre-defined datatype can be declared, I appended a column called 'year' to the Child model of type'year'.

 rails generate migration AddYearToChildren year:year

and changed the migration file as below.

class AddYearToChildren < ActiveRecord::Migration[5.0]
  def up
    execute <<-SQL
      CREATE TYPE year AS ENUM ('Infant', '2_5_years', '5_8_years', '8_10_years', 'More_than_10_years');
    SQL
    add_column :children, :year, :year, index: true
  end

  def down
    remove_column :children, :year

    execute <<-SQL
      DROP TYPE year;
    SQL
  end
end

Finally, rails db:migrate for DB migration changes.

So, now rails enum can be used to store strings in DB.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!