web-dev-qa-db-ja.com

フォームから列挙型を選択して役割を設定します

Ruby on Rails 4.1

列挙型の役割でDeviseを使用しています。現在、ユーザーの作成時にデフォルトの役割を設定しています。 enumロールを設定するユーザーを作成するフォームにフィールドを追加したいのですが。

私は this を読みましたが、それは新しい役割をどのように利用するかを述べていません。

これはUserクラスです

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'

これまでにenumを使用したことがなく、 ドキュメント は役に立ちません。列挙型オプションを表示するにはどうすればよいですか?

14
DDDD

まず、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]}) %>

このステートメントは、ユーザーモデルからロールの配列を取得し、mapメソッドを使用してキーと値のペアの配列を作成します。

35
Daniel Kehoe

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;
}
9
Mohamad

enumsでcollection_selectを使用するために私が用意した最もクリーンな方法は次のとおりです。

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

これは、国際化と順序付けを使用した方法であり、すでに定義されている場合は、current_userロールを自動選択します。これは、次のようなenumロールをすべて含む、roles:カテゴリのロケールファイルがあることを前提としています。

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

Enumは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 DB移行の変更。

したがって、Rails enumを使用してDBに文字列を保存できます。

1
Means