Однозначное наследование с помощью разработки в Rails 4

Я прочитал сообщения здесь, здесь и здесь, но у меня все еще возникают проблемы с внедрением одностраничного наследования.

В идеале я хотел бы иметь два пути регистрации (один для клиентов и один для провайдеров) с общим именем полей, электронной почтой, паролем и подтверждением пароля и регистрацией провайдера с дополнительным полем радиообмена для указания типа провайдера. Я делаю регистрацию с помощью разработки. После нажатия кнопки "Отправить" в регистрационной форме пользователь будет перенаправлен на вторую форму, которая полностью отличается для клиентов и поставщиков (я делаю это, используя страницу редактирования для ресурса).

Как и все, все работает, если я просто делаю это через 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, presence: true, :email => {:ban_disposable_email => true, :message => I18n.t('validations.errors.models.user.invalid_email')}, uniqueness: { case_sensitive: false }

    validates :password, presence: true, 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?
        [email protected]?
    end
end

Клиент:

class Client < User
    validates :industry, presence: true
    validates :city, presence: true
    validates :state, presence: true
    validates :description, presence: true, length: {minimum: 50, maximum: 300}
end

Поставщик:

class Provider < User
    validates :ptype, presence: true
    validates :city, presence: true
    validates :state, presence: true
    validates :education, presence: true
    validates :biography, presence:true, length: {minimum: 50, 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

Ответ 1

Вам нужно указать, какая модель должна быть создана внутри вашего настраиваемого контроллера регистрации (тот, который наследуется от 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, чтобы указать допустимые параметры на основе типа пользователя.

Ответ 2

Просто мысль. Рассматривали ли вы возможность регистрации в качестве пользователя и сохранение параметра типа до тех пор, пока в рабочем процессе не появится.

то есть.

Страница регистрации: Создает пользователя (с параметром, который определяет, какой тип пользователь окажется в конечном итоге)

Вторая страница (к которой вы автоматически перенаправляетесь при создании пользователя или даже регистрируетесь как пользователь, не прошедший через часть 2): Добавляет соответствующую необходимую информацию и тип изменений от пользователя к соответствующему типу STI при отправке.

Другим вариантом будет замена первой кнопки "отправить" на кнопку, которая просто показывает соответствующие дополнительные поля (и настоящую кнопку отправки) через JS.