我有两种类型:
BaseUser < ActiveRecord::Base
和
User < BaseUser
使用Authlogic的身份验证系统执行acts_as_authentic。此继承是使用单表继承
实现的如果新用户注册,我将他注册为用户。但是,如果我已经有一个具有相同电子邮件的BaseUser,我想将该BaseUser更改为数据库中的用户,而不是简单地将所有数据从BaseUser复制到用户并创建新用户(即使用新用户) ID)。这可能吗?感谢。
答案 0 :(得分:75)
史蒂夫的回答是有效的,但由于在调用BaseUser
时实例属于类save
,因此User
中定义的验证和回调将无法运行。您可能希望使用becomes方法转换实例:
user = BaseUser.where(email: "user@example.com").first_or_initialize
user = user.becomes(User) # convert to instance from BaseUser to User
user.type = "User"
user.save!
答案 1 :(得分:18)
您只需将类型字段设置为“用户”并保存记录即可。内存中对象仍将显示为BaseUser,但下次重新加载内存中对象时将是用户
>> b=BaseUser.new
>> b.class # = BaseUser
# Set the Type. In-Memory object is still a BaseUser
>> b.type='User'
>> b.class # = BaseUser
>> b.save
# Retrieve the records through both models (Each has the same class)
>> User.find(1).class # = User
>> BaseUser.find(1).class # User
答案 2 :(得分:4)
基于其他答案,我预计这将在Rails 4.1中起作用:
def update
@company = Company.find(params[:id])
# This separate step is required to change Single Table Inheritance types
new_type = params[:company][:type]
if new_type != @company.type && Company::COMPANY_TYPES.include?(new_type)
@company.becomes!(new_type.constantize)
@company.type = new_type
@company.save!
end
@company.update(company_params)
respond_with(@company)
end
它没有,因为类型改变不会持续。相反,我选择了这种不太优雅的方法,它可以正常工作:
def update
@company = Company.find(params[:id])
# This separate step is required to change Single Table Inheritance types
new_type = params[:company][:type]
if new_type != @company.type && Company::COMPANY_TYPES.include?(new_type)
@company.update_column :type, new_type
end
@company.update(company_params)
respond_with(@company)
end
以下是我用来确认解决方案的控制器测试:
describe 'Single Table Inheritance (STI)' do
class String
def articleize
%w(a e i o u).include?(self[0].to_s.downcase) ? "an #{self}" : "a #{self}"
end
end
Company::COMPANY_TYPES.each do |sti_type|
it "a newly assigned Company of type #{sti_type} " \
"should be #{sti_type.articleize}" do
post :create, { company: attributes_for(:company, type: sti_type) },
valid_session
expect(assigns(:company)).to be_a(sti_type.constantize)
end
end
Company::COMPANY_TYPES.each_index do |i|
sti_type, next_sti_type = Company::COMPANY_TYPES[i - 1],
Company::COMPANY_TYPES[i]
it "#{sti_type.articleize} changed to type #{next_sti_type} " \
"should be #{next_sti_type.articleize}" do
company = Company.create! attributes_for(:company, type: sti_type)
put :update, { id: company.to_param, company: { type: next_sti_type } },
valid_session
reloaded_company = Company.find(company.to_param)
expect(reloaded_company).to be_a(next_sti_type.constantize)
end
end
end