设计和多个"用户"模型

ddi*_*ier 73 ruby-on-rails devise

我正在使用rails 3.2和设计2.0,我对Rails很新.

要求

我想实现以下目标:

  • 具有2个或更多"用户"模型,例如.会员,客户,管理员
  • 所有型号共享一些必填字段(例如电子邮件和密码)
  • 每个模型可能有一些独特的领域(例如,仅限客户的公司)
  • 某些字段可能是共享的但没有相同的验证(例如,客户需要名称,但会员可选)
  • 注册过程中必须填写所有字段,因此表单不同
  • 登录表单应该是唯一的

可能的解决方案

我用Google搜索并搜索了StackOverflow很长一段时间,但对我来说似乎没什么问题(我是一个Java人,对不起:)现在我很困惑.出现了两个解决方案:

单一设计用户

这是最常见的答案.只需创建默认设备用户并在会员 - >用户和客户 - >用户之间创建关系.我关注的是如何为每个模型实现自定义注册过程?我尝试了不同的东西,但一切都结束了!

多个设计用户

这解决了自定义注册过程,对我来说似乎是正确的,但唯一的登录表单是一个阻止程序.我在SO(Devise - 从两个模型登录)上找到了答案,建议覆盖Devise :: Models :: Authenticatable.find_for_authentication(条件).这似乎很复杂(?),因为我是铁杆新手,我想知道这是否有效?

谢谢你的建议!

moh*_*gdy 66

欢迎加入Java guy =),我希望你会喜欢Rails世界.简单地说,要解决您的问题,您有两个解决方案:

  1. 为每个用户在数据库和相应的模型中创建一个表.
  2. 在数据库中创建单个表,并为每个用户类型创建一个模型.这称为单表继承(STI).

哪一个选择?它取决于角色的共同属性.如果它们几乎是常见的(例如,所有都有名称,电子邮件,移动设备......)并且一些属性不同,我强烈推荐STI解决方案.

如何做STI?1.只需使用命令创建设计用户模型和表rails generate devise User 2. type使用迁移将名为string datatype 的列添加到数据库中的用户表.3.为每个用户类型创建一个模型(例如rails g model admin)4.使Admin类继承自用户模型

class Admin < User
end
Run Code Online (Sandbox Code Playgroud)

那就是你做完了=)...... Yupeee

要创建管理员运行命令Admin.create(...),其中点是管理员属性,例如电子邮件,名称,...

我认为这个问题对你也有帮助

  • 谢谢!旁注:我认为 rails g 模型也会为该模型创建迁移文件。在这种情况下,我们不会为 admin 创建一个新表,所以我认为您只需要在模型文件夹中创建一个名为 admin.rb 的文件,而不是使用 rails 生成器。 (2认同)

tw *_*all 26

在尝试各种各样的方法之后,我和你一样,我使用单一的User模型,这将属于多态角色.这似乎是实现单一登录的最简单方法.

用户模型将包含特定于登录的信息.

角色模型将存储特定于每个角色的字段,以及特定于该角色的其他关联.

将通过各个控制器为每个用户类型(角色)自定义新注册,然后为用户构建嵌套属性.

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 
Run Code Online (Sandbox Code Playgroud)

路线 - 只是会员模型的常规内容.

resources :members
#maybe make a new path for New signups, but for now its new_member_path
Run Code Online (Sandbox Code Playgroud)

控制器 - 您必须使用build_user来嵌套属性

#controllers/members_controller.rb
def new
    @member = Member.new
    @member.build_user
end

def create
    #... standard controller stuff
end
Run Code Online (Sandbox Code Playgroud)

视图/构件/ 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 %>
Run Code Online (Sandbox Code Playgroud)

我想指出,没有必要达到nested_form gem; 因为要求是用户只能属于一种类型的角色.


ddi*_*ier 18

我找到了一条路可走,到目前为止我对它很满意.我会在这里为其他人描述.

我选择了单一的"用户"课程.我的问题是为每个伪模型实现自定义注册过程.

型号/ 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
Run Code Online (Sandbox Code Playgroud)

然后我调整了http://railscasts.com/episodes/217-multistep-formshttp://pastie.org/1084054以获得两个带有重写控制器的注册路径:

配置/ 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'
Run Code Online (Sandbox Code Playgroud)

控制器/用户/ 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
Run Code Online (Sandbox Code Playgroud)

我的意见是:

  • new.rb
  • new_client.rb 包括根据向导步骤的部分:
    • _new_client_1.rb
    • _new_client_2.rb
  • new_member.rb 包括根据向导步骤的部分:
    • _new_member_1.rb
    • _new_member_2.rb


Hau*_*eth 6

那有什么不对?只需运行rails g devise:views [model_name],自定义每个注册表单,然后config/initializer/devise.rb放入config.scoped_views = true.