【问题标题】:Select enum from form to set role从表单中选择枚举以设置角色
【发布时间】:2014-08-03 08:00:59
【问题描述】:

Ruby on Rails 4.1

我正在使用带有枚举角色的设计。它当前在创建用户时设置默认角色。我想在创建用户的表单中添加一个字段来设置枚举角色。

我阅读了this,但没有说明如何利用新角色。

这是用户类

devise :database_authenticatable, :registerable, :confirmable,
     :recoverable, :rememberable, :trackable, :validatable
enum role: [:user, :vip, :admin, :developer, :marketing, :support, :translator]
after_initialize :set_default_role, :if => :new_record?

def set_default_role
  self.role ||= :user
end

这是我试图选择一个枚举角色的表单部分:

<div class="form-group">
  <%= f.collection_select :role, User.roles, :id, :enum, {prompt: "Select a role"}, {class: "form-control input-lg"} %>
</div>

错误:

NoMethodError - undefined method `enum' for ["user", 0]:Array:
actionview (4.1.1) lib/action_view/helpers/form_options_helper.rb:761:in `value_for_collection'

我以前从未使用过枚举,the documentation 也没有帮助。如何使枚举选项显示?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 devise enums railsapps


    【解决方案1】:

    首先,enum 不是属性的名称。属性名称为role

    查看rails-devise-pundit 示例应用程序,特别是文件app/views/users/_user.html.erb,它是创建表单以允许管理员更改用户的角色。我怀疑您是否想使用 collection_select 作为助手(如果您有单独的角色模型,这很合适)。相反,一个普通的select 表单助手可以工作。

    这是一个对角色选项进行硬编码的简单示例:

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

    下面是一个更好的例子,它可以避免在表单中对角色进行硬编码:

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

    该语句从 User 模型中获取一个角色数组,并使用map 方法构造一个键值对数组。

    【讨论】:

    • 现在唯一要做的就是覆盖 Devise::RegistrationsController#create 以允许角色。 +1
    • 无需覆盖注册控制器。您可以在应用程序控制器中执行此操作。请参阅我的Rails Devise TutorialDevise README
    • 我想我是不偷懒的。我创建了一个带有 before_filter 的 Users:RegistrationsController :configure_permitted_pa​​rameters that sanitizer.for(:sign_up) 如果我发布该代码,你能告诉我这是否是一种安全的方法吗?
    • 另一种方法:
    【解决方案2】:

    由于您使用的是 Rails 4 或更高版本,因此枚举更加简单。

    给定以下枚举:

    enum role: {
      admin: 1
    }
    

    枚举期望 HTML 选项属性 value 是枚举键:

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

    知道了这一点,你就可以传入枚举键了。

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

    然后使用 CSS 你可以修改外观。

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

    【讨论】:

      【解决方案3】:

      为了将collection_selectenums 一起使用,我提供的最简洁的方法如下:

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

      【讨论】:

      • 如果您正在努力映射自己的数组,您不妨使用select 直接使用它,而无需调用firstsecond. Further, you might as well map User.roles .keys` 而不是 User.roles,因此您不必在其上调用 first,这需要更多的思考才能理解
      • 只是为了线程。他的意思是:f.collection_select :diet_preference, User.roles.keys.map{ |dp| [dp, dp.humanize] }
      【解决方案4】:

      这是我的做法,国际化和排序,如果已经定义,则自动选择 current_user 角色。 它假定您有一个带有角色的语言环境文件:包含所有枚举角色的类别,例如:

      # 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" } %>
      

      【讨论】:

        【解决方案5】:

        由于枚举是 Rails 中整数的包装器,而我想将字符串存储在 DB 中,所以我做了以下操作:

            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] }
             }
        

        以我的形式,

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

        由于我使用的是可以声明预定义数据类型的 PostGREsql 服务器,因此我在类型为“year”的子模型中附加了一个名为“year”的列。

         rails generate migration AddYearToChildren year:year
        

        并将迁移文件更改如下。

        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
        

        最后,rails db:migrate 用于数据库迁移更改。

        所以,现在可以使用 rails 枚举在 DB 中存储字符串。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-10
          • 2022-10-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多