2012-07-20 15 views
5

¿Hay alguna manera de encasillar automáticamente los valores que se almacenan utilizando ActiveRecord :: Base.store?ActiveRecord :: Base.store autocasting automático

Tome este ejemplo totalmente impracticable:

class User < ActiveRecord::Base 
    store :settings, accessors: [ :age ] 
end 

user = User.new(age: '10') 
user.age # => '10' 

Sé que sólo puede reemplazar el método de lectura para la edad para convertirlo en un entero, pero tenía curiosidad por si había una manera de hacerlo sin papeles.

Tratando de evitar esto:

class User < ActiveRecord::Base 
    store :settings, accessors: [ :age ] 

    def age 
    settings[:age].to_i 
    end 
end 

user = User.new(age: '10') 
user.age # => 10 

actualización

buscando algo como:

class User < ActiveRecord::Base 
    store :settings, accessors: {:age => :to_i} 
end 

O:

class User < ActiveRecord::Base 
    store :settings, accessors: {:age => Integer} 
end 

Respuesta

1

A partir de Rails 3.2.7 no hay forma de encasillar automáticamente los valores. Actualizaré esta pregunta si alguna vez encuentro una forma de hacerlo:/

1

Sé de dos maneras de hacerlo. Uno de ellos lo convierte cada vez que se configura. El otro lo convierte solo cuando lo guarda en la base de datos.

Opción uno: Organismo encargo

class User < ActiveRecord::Base 

    ... 

    # public method 
    def age=(age) 
    self.settings[:age] = age.to_i 
    end 

    ... 

end 

En la consola:

$ user.age = '12'  # => "12" 
$ user.age   # => 12 
$ user.age.class  # => Fixnum 
$ user = User.new age: '5' 
$ user.age.class  # => Fixnum 

Opción dos: la llamada before_save (o diferente antes de la llamada)

class User < ActiveRecord::Base 
    before_save :age_to_int 

    ... 

    private 

    def age_to_int 
     # uncomment the if statement to avoid age being set to 0 
     # if you create a user without an age 
     self.age = self.age.to_i # if self.age 
    end 

end 

En la consola

$ user = User.new(age: '10') 
$ user.save 
$ user.age   # => 10 
$ user.age.class  # => Fixnum 

defecto de la opción dos:

$ user.age = '12' 
$ user.age   # => "12" 

que haría uso de la incubadora a medida, si fuera tú. Si desea un valor predeterminado independiente de la columna de la base de datos (que es una cadena), utilice un before_save además del setter.

+0

Gracias por la respuesta, pero esto no es exactamente lo que estaba buscando. Esperaba que hubiera algo integrado en el método DSL que me permitiera establecer los valores predeterminados. –

+0

Creo que va contra el punto de hash en el que puede poner cualquier cosa ... pero mire a su alrededor n buena suerte – AJcodez

+0

De acuerdo, y es un abuso total de ActiveRecord y las bases de datos relacionales. Era más una cosa de curiosidad, supongo. –

0

Es mejor encadenar los métodos de acceso a la tienda en lugar de anularlos porque los métodos creados por estos conjuros mágicos nunca son tan simples como pienso:

define_method(key) do 
    send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash) 
    send(store_attribute)[key] 
end 

Así, en el caso de un número entero, por ejemplo, me gustaría hacer esto:

def age_with_typecasting 
    ActiveRecord::ConnectionAdapters::Mysql2Adapter::Column.value_to_integer(age_without_typecasting) 
end 

alias_method_chain :age, :typecasting 

vez más, no está construido, pero que va a hacer el truco. También utiliza su adaptador de conexión de bases de datos para hacer la conversión de la cadena que está almacenada en la base de datos a la que desea que sea el tipo de valor. Cambie el adaptador según la base de datos que use.

0

Storext agrega tipo fundición y otras características en la parte superior de ActiveRecord::Store.store_accessor.