ruby-on-rails ruby activerecord single-table-inheritance

ruby on rails - Cambio del tipo de clase ActiveRecord en rieles con herencia de tabla única



ruby-on-rails single-table-inheritance (3)

Tengo dos tipos de clases:

BaseUser < ActiveRecord::Base

y

User < BaseUser

que actúa_como_auténtico usando el sistema de autenticación de Authlogic. Esta herencia se implementa usando herencia de tabla única

Si un nuevo usuario se registra, lo registro como Usuario. Sin embargo, si ya tengo un Usuario Base con el mismo correo electrónico, me gustaría cambiar ese Usuario Base a un Usuario en la base de datos sin simplemente copiar todos los datos al Usuario desde el Usuario Base y crear un nuevo Usuario (es decir, con un nuevo Usuario). carné de identidad). es posible? Gracias.


La respuesta de Steve funciona, pero dado que la instancia es de clase BaseUser cuando se llama a save , las validaciones y devoluciones de llamada definidas en User no se ejecutarán. Probablemente quiera convertir la instancia utilizando el método becomes :

user = BaseUser.where(email: "[email protected]").first_or_initialize user = user.becomes(User) # convert to instance from BaseUser to User user.type = "User" user.save!


Puede simplemente configurar el campo de tipo a ''Usuario'' y guardar el registro. El objeto en memoria seguirá mostrándose como un Usuario Base pero la próxima vez que vuelva a cargar el objeto en memoria será un Usuario

>> 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


Según las otras respuestas, esperaba que esto funcionara en 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

No fue así, ya que el cambio de tipo no persistiría. En cambio, opté por este enfoque menos elegante, que funciona correctamente:

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

Y aquí están las pruebas de controlador que utilicé para confirmar la solución:

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