2012-02-21 21 views
7

Tengo 3 campos en mi formulario que no están en mi base de datos: tipo_inicio, horas_iniciativas, apertura_minutos. Quiero actualizar el atributo principal "apertura" (en la base de datos) con estos 3 campos.Rieles - Agregar atributos que no están en el modelo y actualizar el atributo del modelo

Probé muchas cosas que no funcionan.

En realidad tengo:

attr_accessor :opening_type, :opening_hours, :opening_minutes 

    def opening_type=(opening_type) 
    end 
    def opening_type 
    opening_type = opening.split("-")[0] if !opening.blank? 
    end 

    def opening_hours=(opening_hours) 
    end 
    def opening_hours 
    opening_hours = opening.split("-")[1] if !opening.blank? 
    end 

    def opening_minutes=(opening_minutes) 
    end 
    def opening_minutes 
    opening_minutes = opening.split("-")[2] if !opening.blank?  
    end 

He intentado añadir algo como:

def opening=(opening) 
    logger.info "WRITE" 

    if !opening_type.blank? and !opening_hours.blank? and opening_minutes.blank? 
     opening = "" 
     opening << opening_type if !opening_type.blank? 
     opening << "-" 
     opening << opening_hours if !opening_hours.blank? 
     opening << "-" 
     opening << opening_minutes if !opening_minutes.blank? 
    end 
    write_attribute(:opening, opening) 
    end 

    def opening 
    read_attribute(:opening) 
    end 

embargo, los métodos descriptores de acceso no son llamados y creo que opening_type, opening_hours, opening_minutes estaban vacías también si los descriptores de acceso se llamaron ...

Creo que no necesito una devolución de llamada before_save y debería hacer esto reescribiendo los accesadores.

Notas: - Rails 3.0.5, - opening_type, opening_hours:,: opening_minutes podrían estar vacía

EDIT: He actualizado mi código

Respuesta

15

Tenga en cuenta que attr_reader, attr_writer y attr_accessor son sólo las macros para definir sus propios métodos.

# attr_reader(:foo) is the same as: 
def foo 
    @foo 
end 

# attr_writer(:foo) is the same as: 
def foo=(new_value) 
    @foo = new_value 
end 

# attr_accessor(:foo) is the same as: 
attr_reader(:foo) 
attr_writer(:foo) 

Por el momento, sus métodos setter no están haciendo nada especial, así que si sólo cambia a attr_accessor el código será más limpio.

Su otro problema es que su método opening= nunca se está llamando, y esto tiene sentido porque no hay ningún lugar en su código que lo llame. Lo que realmente quiere es que su apertura se establezca después de que se hayan establecido todas las partes individuales. Ahora no hay manera trivial para hacer esto, pero los carriles tiene una devolución de llamada before_validation donde se puede poner el código que se ejecuta después de que los valores se han establecido, pero antes de la validación se ejecuta:

class Shop < ActiveRecord::Base 

    attr_accessor :opening_type, :opening_hours, :opening_minutes 

    before_validation :set_opening 

    private 
    def set_opening 
    return unless opening_type && opening_hours && opening_minutes 
    self.opening = opening_type + "-" + opening_hours + "-" + opening_minutes 
    end 
end 
+0

Tenga en cuenta que esta respuesta asume que solo desea almacenar el campo combinado 'apertura' en la base de datos. Otro enfoque sería almacenar los componentes individuales en la base de datos y construir la cadena combinada dinámicamente a pedido. Dependiendo de sus requisitos, puede ser un mejor enfoque para usted. – Gareth

+0

Obtengo esta base de datos con el campo de apertura. Esta base de datos se sincroniza con una aplicación de teléfono inteligente y no puedo cambiar su estructura para almacenar los 3 campos diferentes. ;-) El problema con una devolución de llamada before_validation es que no maneja el caso cuando vamos a editar el formulario ... y donde tengo que truncar el campo de apertura en 3 vars ... para el formulario. Sé que puedo hacerlo manualmente pero pensé que había un mejor enfoque para hacerlo con los accesorios ... –

+0

Todo es cierto, pero su sugerencia de anular 'opening =' romperá muchas cosas. Además, es una idea muy esquemática tener un método setter que descarte totalmente el parámetro que se transfiere. Es mejor tener un método separado (como mi 'set_opening') que aclare lo que está haciendo. Usted no * tiene * que usar antes de la validación para llamar a ese método, pero le recomiendo seriamente que sea un método diferente – Gareth

0

en lugar de

attr_reader :opening_type, :opening_hours, :opening_minutes 

que necesita

attr_accessor :opening_type, :opening_hours, :opening_minutes 
attr_reader :opening_type, :opening_hours, :opening_minutes 

hf ...

// Are: opening_type,: opening_hours,: opening_minutes campos reales? Si es así, ¿solo necesitas esto?

attr_accessor: apertura attr_reader: apertura

+0

Ok, lo cambió por attr_accessor. Pero los accesadores de apertura no se llaman ... –

+0

ver actualización, .... – davidb

+0

No. El campo real es "abrir" en mi base de datos. Necesito concat 3 campos enviados desde mi formulario: opening_type, opening_hours, opening_minuts para llenar el campo principal de "apertura". Estos 3 campos no están en la base de datos. Actualicé la primera publicación. –

Cuestiones relacionadas