J'utilise Rails 3.2 et imagine 2.0 et je suis assez nouveau dans Rails.
J'aimerais atteindre les objectifs suivants:
J'ai googlé et recherché StackOverflow pendant assez longtemps, mais rien ne me semble juste (je suis un gars Java, désolé :) et maintenant je suis assez confus. Deux solutions sont apparues:
C'est la réponse la plus fréquente. Créez simplement l'utilisateur par défaut et créez des relations entre Membre -> Utilisateur et Client -> Utilisateur. Ma préoccupation ici est de savoir comment puis-je réaliser un processus d'enregistrement personnalisé pour chaque modèle? J'ai essayé différentes choses mais tout s'est terminé comme un gâchis!
Cela résout le processus d'enregistrement personnalisé et me semble juste, mais le formulaire de connexion unique est un bloqueur. J'ai trouvé une réponse sur SO ( Devise - connexion à partir de deux modèles ) qui suggère de remplacer Devise :: Models :: Authenticatable.find_for_authentication (conditions). Cela semble compliqué (?) et comme je suis nouveau sur Rails, j'aimerais savoir si ça pourrait marcher?
Merci pour vos conseils!
J'ai trouvé un chemin à parcourir et j'en suis assez satisfait jusqu'à présent. Je vais le décrire ici pour les autres.
Je suis allé avec la seule classe "utilisateur". Mon problème était de réaliser un processus d'enregistrement personnalisé pour chaque pseudo modèle.
model/user.rb:
class User < ActiveRecord::Base
devise :confirmable,
:database_authenticatable,
:lockable,
:recoverable,
:registerable,
:rememberable,
:timeoutable,
:trackable,
:validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :role
as_enum :role, [:administrator, :client, :member]
validates_as_enum :role
## Rails 4+ for the above two lines
# enum role: [:administrator, :client, :member]
end
Ensuite, j'ai adapté http://railscasts.com/episodes/217-multistep-forms et http://pastie.org/1084054 pour avoir deux chemins d'enregistrement avec un surchargé manette:
config/routes.rb:
get 'users/sign_up' => 'users/registrations#new', :as => 'new_user_registration'
get 'clients/sign_up' => 'users/registrations#new_client', :as => 'new_client_registration'
post 'clients/sign_up' => 'users/registrations#create', :as => 'client_registration'
get 'members/sign_up' => 'users/registrations#new_member', :as => 'new_member_registration'
post 'members/sign_up' => 'users/registrations#create', :as => 'member_registration'
contrôleurs/utilisateurs/registrations_controller.rb:
J'ai créé une classe assistant qui connaît les champs à valider à chaque étape
class Users::RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
session[:user] ||= { }
@user = build_resource(session[:user])
@wizard = ClientRegistrationWizard.new(current_step)
respond_with @user
end
# GET /clients/sign_up
def new_client
session[:user] ||= { }
session[:user]['role'] = :client
@user = build_resource(session[:user])
@wizard = ClientRegistrationWizard.new(current_step)
render 'new_client'
end
# GET /members/sign_up
def new_member
# same
end
# POST /clients/sign_up
# POST /members/sign_up
def create
session[:user].deep_merge!(params[:user]) if params[:user]
@user = build_resource(session[:user])
@wizard = ClientRegistrationWizard.new(current_step)
if params[:previous_button]
@wizard.previous
elsif @user.valid?(@wizard)
if @wizard.last_step?
@user.save if @user.valid?
else
@wizard.next
end
end
session[:registration_current_step] = @wizard.current_step
if @user.new_record?
clean_up_passwords @user
render 'new_client'
else
#session[:registration_current_step] = nil
session[:user_params] = nil
if @user.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(:user, @user)
respond_with @user, :location => after_sign_up_path_for(@user)
else
set_flash_message :notice, :"signed_up_but_#{@user.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with @user, :location => after_inactive_sign_up_path_for(@user)
end
end
end
private
def current_step
if params[:wizard] && params[:wizard][:current_step]
return params[:wizard][:current_step]
end
return session[:registration_current_step]
end
end
et mes vues sont:
new.rb
new_client.rb
y compris un partiel selon l'étape de l'assistant: _new_client_1.rb
_new_client_2.rb
new_member.rb
y compris un partiel selon l'étape de l'assistant: _new_member_1.rb
_new_member_2.rb
Bienvenue à bord Java guy =), j'espère que vous apprécierez le monde Rails. Simplement, pour résoudre votre problème, vous avez 2 solutions:
Lequel choisir? Cela dépend des attributs communs des rôles. S'ils sont presque courants (par exemple tous ont un nom, un email, un mobile, ...) et que quelques attributs sont différents, je recommande fortement la solution STI.
Comment faire l'IST? 1. Créez simplement le modèle utilisateur et la table du modèle à l'aide de la commande Rails generate devise User
2. Ajoutez une colonne nommée type
avec le type de données chaîne à la table utilisateur de la base de données à l'aide d'une migration. 3. Pour chaque type d'utilisateur, créez un modèle (par exemple Rails g model admin
) 4. Faites en sorte que la classe Admin hérite du modèle d'utilisateur
class Admin < User
end
Voilà c'est fait =) ... Yupeee
Pour créer un administrateur, exécutez la commande Admin.create(...)
où les points correspondent aux attributs administrateur, par exemple l'e-mail, le nom, ...
Je pense que cela question pourrait aussi vous aider
Je suis dans la même situation que vous, après avoir essayé toutes sortes d'approches, je suis allé avec un seul modèle utilisateur, qui appartiendrait à des rôles polymorphes. Cela semble être le moyen le plus simple de réaliser une connexion unique.
Le modèle utilisateur contiendrait les informations spécifiques à la connexion uniquement.
Le modèle de rôle stockerait des champs spécifiques à chaque rôle, ainsi que d'autres associations spécifiques au rôle.
Les nouvelles inscriptions seraient personnalisées pour chaque type d'utilisateur (rôles) via des contrôleurs individuels, puis créer des attributs imbriqués pour l'utilisateur.
class User < ActiveRecord::Base
#... devise code ...
belongs_to :role, :polymorphic => true
end
class Member < ActiveRecord::Base
attr_accessible :name, :tel, :city #etc etc....
attr_accessible :user_attributes #this is needed for nested attributes assignment
#model specific associations like
has_many :resumes
has_one :user, :as => :role, dependent: :destroy
accepts_nested_attributes_for :user
end
Routes - juste des trucs réguliers pour le modèle Member.
resources :members
#maybe make a new path for New signups, but for now its new_member_path
Controller - vous devez build_user pour les attributs imbriqués
#controllers/members_controller.rb
def new
@member = Member.new
@member.build_user
end
def create
#... standard controller stuff
end
vues/membres/new.html.erb
<h2>Sign up for new members!</h2>
<%= simple_form_for @member do |f| %>
# user fields
<%= f.fields_for :user do |u| %>
<%= u.input :email, :required => true, :autofocus => true %>
<%= u.input :password, :required => true %>
<%= u.input :password_confirmation, :required => true %>
<% end %>
# member fields
<%= f.input :name %>
<%= f.input :tel %>
<%= f.input :city %>
<%= f.button :submit, "Sign up" %>
<% end %>
Je voudrais souligner qu'il n'y a AUCUN BESOIN à atteindre pour la gemme nested_form; car l'exigence est que l'utilisateur ne puisse appartenir qu'à un seul type de rôle.
Alors, qu'est-ce qui ne va pas? Exécutez simplement Rails g devise:views [model_name]
, personnalisez chaque formulaire d'inscription et dans config/initializer/devise.rb
il suffit de mettre config.scoped_views = true
.