73 votes

concevoir et multiplier les modèles "utilisateurs

J'utilise rails 3.2 et devise 2.0 et je suis assez novice en matière de Rails.

Exigences

J'aimerais réaliser ce qui suit :

  • avoir 2 ou plusieurs modèles "utilisateur", par exemple Membre, Client, Admin
  • tous les modèles partagent certains champs obligatoires (par exemple, l'email et le mot de passe)
  • Chaque modèle peut avoir des champs uniques (par exemple, la société pour le client uniquement).
  • certains champs peuvent être partagés mais ne pas avoir la même validation (par exemple, le nom est obligatoire pour le client mais facultatif pour le membre).
  • tous les champs doivent être remplis lors de la procédure d'inscription, les formulaires sont donc différents
  • le formulaire de connexion doit être unique

Solutions possibles

J'ai cherché sur Google et StackOverflow pendant un bon moment, mais rien ne me semble correct (je suis un gars de Java, désolé :) et maintenant je suis assez confus. Deux solutions sont apparues :

Utilisateur d'un seul appareil

C'est la réponse la plus fréquente. Il suffit de créer le devise User par défaut et de créer des relations entre Member-->User et Customer-->User. Ce qui me préoccupe ici, c'est de savoir comment réaliser un processus d'enregistrement personnalisé pour chaque modèle ? J'ai essayé différentes choses mais tout s'est terminé en désordre !

Utilisateurs de plusieurs appareils

Cela résout le problème du processus d'enregistrement personnalisé et me semble correct, mais le formulaire de connexion unique est un obstacle. J'ai trouvé une réponse sur SO ( Devise - connexion à partir de deux modèles ) qui suggère de surcharger Devise::Models::Authenticatable.find_for_authentication(conditions). Cela semble compliqué ( ?) et comme je suis nouveau sur rails, j'aimerais savoir si cela peut fonctionner ?

Merci pour vos conseils !

67voto

mohamagdy Points 1302

Bienvenue à bord du gars de Java =), j'espère que vous apprécierez le monde de Rails. Simplement, pour résoudre votre problème, vous avez 2 solutions :

  1. Pour chaque utilisateur, créez une table dans la base de données et le modèle correspondant.
  2. Créez une table unique dans la base de données et pour chaque type d'utilisateur, créez un modèle. C'est ce qu'on appelle l'héritage d'une seule table (STI).

Lequel choisir ? Cela dépend des attributs communs des rôles. S'ils sont presque communs (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'ITS ? 1. Créez simplement le modèle et la table de l'utilisateur devise en utilisant la commande rails generate devise User 2. Ajoutez une colonne nommée type avec le type de données string à la table utilisateur dans la base de données en utilisant une migration. 3. Pour chaque type d'utilisateur, créez un modèle (par exemple rails g model admin ) 4. Faire en sorte que la classe Admin hérite du modèle utilisateur

class Admin < User
end

C'est tout, vous avez terminé =) ... Yupeee

Pour créer un administrateur, exécutez la commande Admin.create(...) où les points sont les attributs de l'administrateur, par exemple l'email, le nom, ...

Je pense que ce question pourrait vous aider aussi

26voto

tw airball Points 781

Je suis dans la même situation que vous, après avoir essayé toutes sortes d'approches, j'ai opté pour un modèle d'utilisateur unique, 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 à l'ouverture de session uniquement.

Le modèle de rôle stockerait les champs spécifiques à chaque rôle, ainsi que d'autres associations spécifiques au rôle.

Les nouveaux enregistrements seraient personnalisés pour chaque type d'utilisateur (rôles) via des contrôleurs individuels, puis en construisant 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 ordinaires pour le modèle de membre.

resources :members
#maybe make a new path for New signups, but for now its new_member_path

Contrôleur -- vous devez construire_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/nouveau.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 tiens à souligner qu'il n'est PAS nécessaire d'utiliser le formulaire imbriqué, puisque l'exigence est que l'utilisateur ne peut appartenir qu'à un seul type de rôle.

18voto

c_inconnu Points 439

J'ai trouvé un moyen d'y aller et j'en suis assez satisfait jusqu'à présent. Je vais la décrire ici pour les autres.

J'ai opté pour la classe unique "utilisateur". Mon problème était de réaliser un processus d'enregistrement personnalisé pour chaque pseudo-modèle.

modèle/utilisateur.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

Puis j'ai adapté http://railscasts.com/episodes/217-multistep-forms y http://pastie.org/1084054 pour avoir deux chemins d'enregistrement avec un contrôleur surchargé :

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'

controllers/users/registrations_controller.rb :

J'ai créé une classe d'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 opinions sont :

  • new.rb
  • new_client.rb incluant un partiel selon l'étape de l'assistant :
    • _new_client_1.rb
    • _new_client_2.rb
  • new_member.rb incluant un partiel selon l'étape de l'assistant :
    • _new_member_1.rb
    • _new_member_2.rb

6voto

hauleth Points 8253

Alors, qu'est-ce qui ne va pas ? Cours juste rails g devise:views [model_name] personnaliser les formulaires d'enregistrement et les formulaires d'inscription config/initializer/devise.rb mets juste config.scoped_views = true .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X