我在这篇文章中关注 Vampire 的解决方案,并且在创建具有关联子类的新用户时遇到了一些问题。
我有一个与两个子类(学生和编辑器)具有多态关联的用户模型。新用户注册也有自己的控制器。当我填写表格时,我收到一条错误消息,指出电子邮件和密码不能为空,即使它们不是。如何编写 create 方法以接受来自两个可能的子类之一的属性。
编辑器模型
require 'carrierwave/orm/activerecord'
class Editor < ActiveRecord::Base
has_one :user, :as => :rolable
belongs_to :school
mount_uploader :image, ImageUploader
end
用户模型(不确定我是否需要在这里使用接受嵌套属性)
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
belongs_to :rolable, :polymorphic => true
has_many :editors
has_many :students
accepts_nested_attributes_for :editors
accepts_nested_attributes_for :students
#has_many :applications
#has_many :editors, :through => :applications
#has_and_belongs_to_many :schools
end
新用户表单
<center>
<div class="hero-unit">
<h2>Sign up</h2>
<% params[:user][:user_type] ||= 'student'
if ["student", "editor"].include? params[:user][:user_type].downcase
child_class_name = params[:user][:user_type].downcase.camelize
user_type = params[:user][:user_type].downcase
else
child_class_name = "Student"
user_type = "student"
end
resource.rolable = child_class_name.constantize.new if resource.rolable.nil?
%>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= my_devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<%= fields_for resource.rolable do |rf| %>
<% render :partial => "#{child_class_name.underscore}_fields", :locals => { :f => rf } %>
<% end %>
<%= hidden_field :user, :user_type, :value => user_type %>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render :partial => "devise/shared/links" %>
</div>
</center>
用户注册控制器
class UserRegistrationsController < Devise::RegistrationsController
def user_params
params.require(:user).permit(:email, :password, :password_confirmation,)
end
def new
super
end
def update
super
end
def edit
super
end
def destroy
super
end
def create
# Building the user, I assume.
build_resource
# crate a new child instance depending on the given user type
child_class = params[:user][:user_type].camelize.constantize
resource.rolable = child_class.new(user_params[child_class.to_s.underscore.to_sym])
# first check if child instance is valid
# cause if so and the parent instance is valid as well
# it's all being saved at once
valid = resource.valid?
valid = resource.rolable.valid? && valid
# customized code end
if valid && resource.save # customized code
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => redirect_location(resource_name, resource)
else
set_flash_message :notice, :inactive_signed_up, :reason => inactive_reason(resource) if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords(resource)
respond_with_navigational(resource) { render :new }
end
end
end