2009-01-12 11 views
10

Estoy usando single table inheritance en mi aplicación de rieles, y quiero establecer explícitamente el tipo de una instancia.Rails Single Table Herencia: ¿Cuál es la mejor forma de establecer explícitamente el tipo?

Tengo lo siguiente;

class Event < ActiveRecord::Base 
class SpecialEvent < Event 

que se implementa a través de herencia de tabla única.

SpecialEvent.new funciona como se esperaba, pero yo quiero ser capaz de hacer cosas como

Event.new(:type => 'SpecialEvent') 

Así que puedo crear diferentes sub_types fácilmente en la aplicación.

Sin embargo, esto no funciona y parece establecer :type en nil, no en el valor que configuré; Sospecho que esto se debe a que al llamar al Event.new sobrescribe el argumento :type.

¿Alguien ha tenido una buena manera de hacerlo?

+0

¿Quiere decir que desea crear subtipos sobre la marcha? – Bill

+0

No, quiero crear instancias de subtipos, donde quiero determinar programáticamente qué subtipo son – DanSingerman

Respuesta

21

Si usted está tratando de crear dinámicamente una instancia de un subtipo, y usted tiene el tipo como una cadena, se puede hacer esto:

'SpecialEvent'.constantize.new() 
+3

Solo una nota rápida aquí - asegúrese de estar desinfectando la entrada si esta cadena proviene de una publicación de formulario o similar - usted No quiero llamar a #constantize en datos arbitrarios de una fuente posiblemente maliciosa, por ejemplo, 'klass.constantize.new() if valid_class_names.include? (klass)' –

5

No, quiero crear instancias de subtipos , donde quiero programación determino qué sub_type son - HERMAND

se puede usar un factory pattern, aunque he oído re Por último, la gente frunce el ceño por el uso excesivo de este patrón. Básicamente, utilizar la fábrica para crear los tipos reales que desea obtener

class EventFactory 
    def EventFactory.create_event(event_type) 
    event_type.constantize.new() 
    end 
end 
0

Al parecer, los carriles no le permiten establecer el tipo de forma directa. Esto es lo que hago ...

klass_name = 'Foo' 
... 
klass = Class.const_get(klass_name) 
klass.new # Foo.new 

Creo .constantize es un atajo del reflector Rails. const_get es un método de Ruby en clase y módulo.

+3

Esto no funcionará si está utilizando espacios de nombres para sus clases , es decir. Class.const_get ('Foo :: Bar') dará como resultado un error. 'Foo :: Bar'.constantize funcionará sin embargo. –

14

de "pragmático - Agile Web Development con rieles 3ª edición", página 380

También hay una restricción menos obvia (con ITS). El tipo de atributo también es el nombre de un método incorporado de Ruby, por lo que acceder directamente al para establecer o cambiar el tipo de una fila puede dar como resultado mensajes extraños de Ruby .En su lugar, el acceso implícitamente mediante la creación de objetos de la clase apropiada , o acceder a ella a través de la interfaz de indexación el modelo de objeto, usando algo como esto:

persona [: tipo] = 'administrador'

hombre, este libro realmente rocas

2

a mí me suena como que va a necesitar algo de mojo en la acción event#create:

type = params[:event].delete(:type) 

# check that it is an expected value!!! 
die unless ['Event', 'SpecialEvent'].include(type) 

type.constantize.new(params[:event]) 
0

De entrada, estoy de acuerdo en que las ITS a menudo NO son la mejor forma de tratar las cosas. Polimorfismo, sí, pero a menudo es mejor usar una asociación polimórfica que STI.

Dicho esto, tenía un sistema en el que ITS era importante. Era un sistema judicial y cosas como los casos judiciales eran notablemente similares en todos sus tipos y generalmente compartían todos sus atributos esenciales. Sin embargo, un caso civil y un caso criminal difieren en los elementos que manejan. Esto sucedió en varios niveles en el sistema, así que resumí mi solución.

https://github.com/arvanasse/sti_factory

larga historia, que utiliza un método de fábrica para aprovechar el enfoque común ha descrito anteriormente. Como resultado, el controlador puede permanecer neutral/ignorante del tipo particular de clase de STI que está creando.

0

Puede utilizar el método Rails safe_constantize, que asegurará que el objeto/clase realmente exista.

Por ejemplo:

def typeify(string) 
    string.classify.safe_constantize 
end 

new_special_event = typeify('special_event').new 
Cuestiones relacionadas