7

Tengo las siguientes clases:¿Se pueden usar atributos anidados en combinación con la herencia?

  • Proyecto
  • persona
  • persona>desarrollador
  • persona> Administrador de

En el modelo Project me han añadido las siguientes declaraciones:

has_and_belongs_to_many :people 
accepts_nested_attributes_for :people 

y por supuesto las declaraciones apropiadas en la clase Person. ¿Cómo puedo agregar un Developer a un Project a través del método nested_attributes? El siguiente no funciona:

@p.people_attributes = [{:name => "Epic Beard Man", :type => "Developer"}] 
@p.people 
=> [#<Person id: nil, name: "Epic Beard Man", type: nil>] 

Como se puede ver los atributos type se establece a nil en lugar de "Developer".

Respuesta

5

Me encontré con un problema similar hace unos días. La columna de herencia (es decir, type) en un modelo de STI es un atributo protegido. Haga lo siguiente para anular la protección predeterminada en su clase Person.

Rails 2.3

class Person < ActiveRecord::Base 

private 
    def attributes_protected_by_default 
    super - [self.class.inheritance_column] 
    end 
end 

Rails 3

Consulte la solution sugerido por @tokland.

Advertencia:

está sustituyendo el sistema protegido atributo.

Referencia:

SO Question on the topic

+0

nota: esto funciona para Rails 2.3, ver mi respuesta a continuación para Rails 3 – tokland

+0

@tokland, no había visitado esta pregunta por algún tiempo. He actualizado mi respuesta con una solución de Rails 3. –

+0

genial. Escribiría un simple 'def self.attributes_protected_by_default', pero lo que sea. – tokland

4

Parches anterior no funciona para mí, pero esto lo hicieron (Rails3):

class ActiveRecord::Reflection::AssociationReflection 
    def build_association(*options) 
    if options.first.is_a?(Hash) and options.first[:type].presence 
     options.first[:type].to_s.constantize.new(*options) 
    else 
     klass.new(*options) 
    end 
    end 
end 

Foo.bars.build (: Tipo =>' Baz ').== clase Baz

+0

Esta solución funciona para asociaciones, pero no para la construcción de objetos STI. He actualizado mi respuesta con una solución genérica de Rails 3. –

7

Solución para Rails3: attributes_protected_by_default ahora una clase de método:

class Person < ActiveRecord::Base 

    private 

    def self.attributes_protected_by_default 
    super - [inheritance_column] 
    end 
end 
+0

+1 esto es conciso .. –

+0

Nota: Asegúrese de poner esto cerca de la parte superior de la clase, * antes * de cualquier llamada a 'attr_protected'. La primera llamada a 'attr_protected' hará que llame a cualquier versión de' attributes_protected_by_default' actualmente definida, que será la versión predeterminada de AR a menos que lo haya anulado en ese punto ... –

0

Para aquellos de nosotros usando Mongoid, que tendrá que hacer el campo _type accesible:

class Person 
    include Mongoid::Document 
    attr_accessible :_type 
end 
Cuestiones relacionadas