Ruby on Rails 4.1
J'utilise Devise avec un rôle enum. Il définit actuellement un rôle par défaut lors de la création de l'utilisateur. Je souhaite ajouter un champ au formulaire qui crée des utilisateurs pour définir le rôle enum.
J'ai lu ceci mais cela ne dit pas comment utiliser les nouveaux rôles.
C'est la classe utilisateur
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
C’est la partie du formulaire où j’essaie de choisir un rôle enum:
<div class="form-group">
<%= f.collection_select :role, User.roles, :id, :enum, {Prompt: "Select a role"}, {class: "form-control input-lg"} %>
</div>
L'erreur:
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'
Je n'ai jamais utilisé enum auparavant et la documentation n'est pas utile. Comment puis-je afficher les options enum?
Pour commencer, enum
n'est pas le nom d'un attribut. Le nom de l'attribut est role
.
Jetez un coup d’œil à l’application Rails-devise-pundit example, plus précisément au fichier app/views/users/_user.html.erb qui est un partiel qui crée un formulaire permettant à changer le rôle d'un utilisateur. Je doute que vous souhaitiez utiliser un collection_select
pour helper (qui convient si vous avez un modèle de rôle distinct). Au lieu de cela, un assistant de forme select
ordinaire fonctionnera.
Voici un exemple simple qui code les options de rôle:
<%= f.select(:role, [['User', 'user'], ['Vip', 'vip'], ['Admin', 'admin']]) %>
Voici un meilleur exemple qui évite de coder en dur les rôles sous la forme:
<%= f.select(:role, User.roles.keys.map {|role| [role.titleize,role]}) %>
L'instruction obtient un tableau de rôles à partir du modèle utilisateur et construit un tableau de paires clé-valeur à l'aide de la méthode map
.
Puisque vous utilisez Rails 4 ou supérieur, les énumérations sont encore moins compliquées.
Étant donné l'énumération suivante:
enum role: {
admin: 1
}
Enums s'attend à ce que l'attribut d'option HTML value
soit la clé enum:
<option value="admin"> <!-- As opposed to: <option value="1"> -->
Sachant cela, vous pouvez passer les clés enum.
<%= f.select :role, User.roles.keys, {}, class: 'user-roles-select' %>
Ensuite, en utilisant CSS, vous pouvez modifier l'apparence.
.user-roles-select option {
text-transform: capitalize;
}
La manière la plus propre que j'ai utilisée pour utiliser collection_select
avec enum
s est la suivante:
f.collection_select :diet_preference, User.roles.map{ |dp| [dp.first, dp.first.humanize] }, :first, :second
Voici comment je l'ai fait, avec l'internationalisation et la commande, et la sélection automatique du rôle current_user si déjà défini.
# 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" } %>
Comme enum est un wrapper pour un entier dans Rails et que je voulais plutôt stocker des chaînes dans une base de données, j'ai procédé comme suit:
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] }
}
Sous ma forme,
<%= f.select :age, options_for_select(Child::AGE_YEARS, params[:age]), include_blank: 'Select an age-group.' %>
Comme j'utilisais le serveur PostGREsql dans lequel un type de données prédéfini peut être déclaré, j'ai ajouté une colonne appelée "année" au modèle Child de type "année".
Rails generate migration AddYearToChildren year:year
et changé le fichier de migration comme ci-dessous.
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
Enfin, Rails db:migrate
pour les changements de migration de base de données.
Ainsi, Rails enum peut maintenant être utilisé pour stocker des chaînes dans la base de données.