我已经阅读了
here,here和
here的帖子,但是我仍然无法实现单表继承.
理想情况下,我想要有两个注册路径(一个用于客户端,一个用于提供程序),具有通用字段名称,电子邮件,密码和confirm_password,并且提供者注册具有一个额外的单选按钮字段来指定提供者类型.我正在通过设计进行注册.点击注册表单上的提交后,用户将被重定向到对于客户端和提供者完全不同的第二个表单(我一直在使用资源的编辑页面).
就像现在一样,如果我只是通过User进行操作,一切正常,但一旦添加了单表继承,注册表就告诉我他们缺少第二个表单的要求.
这是我的config / routes.rb
Rails.application.routes.draw do devise_for :users,:controllers => {:sessions => "sessions"},:skip=> :registrations devise_for :clients,:providers,:skip=> :sessions resources :clients resources :providers root :to=>'pages#home' match '/home',to: 'pages#home',via: 'get' end
我的机型看起来如下:
用户:
class User < ActiveRecord::Base before_save {self.email = email.downcase} devise :database_authenticatable,:registerable,:recoverable,:rememberable,:trackable,:validatable validates :name,presence: true,length: {maximum: 50} validates :email,:email => {:ban_disposable_email => true,:message => I18n.t('validations.errors.models.user.invalid_email')},uniqueness: { case_sensitive: false } validates :password,length: {minimum: 6},:if=>:password_validation_required? logo_TYPES = ['image/jpeg','image/png','image/gif'] has_attached_file :avatar,:styles => {:medium => "300x300>",:square=>"200x200>",:thumb => "100x100>" },:default_url => '/assets/missing_:style.png' validates_attachment_content_type :avatar,:content_type => logo_TYPES def password_validation_required? !@password.blank? end end
客户:
class Client < User validates :industry,presence: true validates :city,presence: true validates :state,presence: true validates :description,length: {minimum: 50,maximum: 300} end
提供者:
class Provider < User validates :ptype,presence: true validates :education,presence: true validates :biography,presence:true,maximum: 300} validates_format_of :linkedin,:with => URI::regexp(%w(http https)) validates :resume,presence: true has_many :disciplines end
这里是我的控制器:
class SessionsController < Devise::SessionsController def create rtn = super sign_in(resource.type.underscore,resource.type.constantize.send(:find,resource.id)) unless resource.type.nil? rtn end end class RegistrationsController < Devise::RegistrationsController protected def after_sign_up_path_for(resource) if resource.is_a?(User) if current_user.is_a?(Client) edit_client_path(current_user.id) elsif current_user.is_a?(Provider) edit_provider_path(current_user.id) end else super end end end class ClientsController < ApplicationController def show @client = Client.find(params[:id]) end def edit @client = Client.find(params[:id]) end def update @client = Client.find(params[:id]) if @client.update_attributes(client_params_edit) flash[:success] = "Profile Updated" redirect_to @client else flash[:failure] = "Profile Information Invalid" render 'edit' end end def client_params_edit params.require(:client).permit(:avatar,:industry,:city,:website,:description) end end
提供者控制器非常相似.
最后,这是我的schema.rb:
ActiveRecord::Schema.define(version: 20140628213816) do create_table "disciplines",force: true do |t| t.integer "years" t.string "description" t.integer "user_id" end create_table "users",force: true do |t| t.string "name" t.string "email" t.string "avatar_file_name" t.string "avatar_content_type" t.integer "avatar_file_size" t.datetime "avatar_updated_at" t.string "password_digest" t.string "industry" t.string "city" t.string "state" t.string "website" t.string "description" t.string "encrypted_password",default: "",null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.integer "sign_in_count",default: 0,null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" t.datetime "created_at" t.datetime "updated_at" t.string "type" t.string "ptype" t.string "education" t.string "resume_file_name" t.string "resume_content_type" t.integer "resume_file_size" t.datetime "resume_updated_at" end add_index "users",["email"],name: "index_users_on_email",unique: true add_index "users",["reset_password_token"],name: "index_users_on_reset_password_token",unique: true end
解决方法
您需要指定在自定义注册控制器(从Devise :: RegistrationsController继承的)中实例化哪个模型.
您必须覆盖名为resource_class的受保护方法有点像这样:
def resource_class # for example you pass type inside params[:user] klass = params[:user].try(:[],:type) || 'Client' # we don't want wrong class to be instantiated raise ArgumentError,'wrong user class' unless ['Client','Provider'].include?(klass) # transform string to class klass.constantize end
此外,您也可能希望覆盖sign_up_params以根据用户类型指定允许的参数.