1. ホーム
  2. ruby-on-rails

ユーザー」モデルの工夫と複数

2023-09-22 08:59:07

質問

rails 3.2とdevise 2.0を使っているのですが、Railsはかなり初心者なんです。

必要条件

以下を実現したい。

  • 2つ以上のユーザーモデル(例:Member、Customer、Admin)を持っている。
  • すべてのモデルがいくつかの必須フィールドを共有する (例: メールアドレスとパスワード)
  • 各モデルは、いくつかのユニークなフィールドを持つことができます (例: Customerのみのcompany)
  • いくつかのフィールドは共有されますが、同じバリデーションはありません (例: name は Customer では必須ですが、Member ではオプションです)
  • すべてのフィールドは、登録プロセスで入力する必要があるため、フォームは異なります。
  • ログインフォームは一意であるべきです。

可能な解決策

私はかなり長い間グーグルやStackOverflowで検索しましたが、私には何も正しいとは思えず(私はJavaの人です、すみません : )、今私はかなり混乱しています。2つのソリューションが出てきました。

単一のデバイスのユーザー

最も多い回答です。デフォルトのdevise Userを作成し、Member-->UserとCustomer-->Userの間のリレーションを作成するだけです。 ここで気になるのは、モデルごとにカスタマイズされた登録処理を実現するにはどうすればいいのか、ということです。

複数のデバイスのユーザー

これはカスタム登録プロセスを解決し、私には正しいように思えますが、ユニークなログインフォームがブロッカーです。SOに回答がありました( 工夫 - 2つのモデルからログイン )で、Devise::Models::Authenticatable.find_for_authentication(conditions)をオーバーライドすることを示唆しています。 それは複雑なようです(?)そして、私はrailsに新しいので、私はそれが動作することができるかどうかを知りたいのですが?

アドバイスありがとうございました。

どのように解決するのですか?

私はある方法を見つけ、今のところかなり満足しています。他の人のためにここに記述しておきます。

私は、単一の "user" クラスを使用しました。私の問題は、各擬似モデルに対してカスタマイズされた登録プロセスを実現することでした。

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

次に http://railscasts.com/episodes/217-multistep-forms http://pastie.org/1084054 で、オーバーライドされたコントローラで2つの登録パスを持つことができます。

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:

各ステップで検証するフィールドを知るウィザードクラスを作りました。

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

と私の見解を述べました。

  • new.rb
  • new_client.rb ウィザードのステップに従ってパーシャルを含む。
    • _new_client_1.rb
    • _new_client_2.rb
  • new_member.rb ウィザードのステップに従って、パーシャルを含む。
    • _new_member_1.rb
    • _new_member_2.rb