2012-01-09 6 views
5

He rastreado la API y pasé dos noches mirando este código y, lamentablemente, mientras percibo que estoy cerca del solución, no puedo hacer que funcione. Tengo un modelo que representa los cambios, que entre otros atributos tienen una hora de inicio.Capturando una excepción planteada en el acceso personalizado antes de llegar a la validación del modelo (y mostrándola al usuario en errores [])

create_table "shifts", :force => true do |t| 
    t.datetime "start" 

el usuario interactúa con esto como un tiempo simple como la fecha se establece en otro lugar, por lo que han establecido métodos de acceso virtuales para obtener y definir.

class Shift < ActiveRecord::Base 
    def start_time 
    start.strftime("%H:%M") 
    end 

    def start_time=(time) 
    date = start.midnight 
    self.start = add_string_time_to_date(date, time) 
    end 

    def add_string_time_to_date(date, string_time) 
    t = DateTime.strptime(string_time, "%H:%M") 
    DateTime.new(date.year, date.month, date.mday, t.hour, t.min) 
    end 
end 

Todo esto funciona bien cuando se manipula a través de un controlador estándar con @shift.update_attributes(params[:shift]) uno provisto entra en el momento en el formato esperado.

Me gustaría validar el formato de hora introducido, pero no es tan simple como usar el método de abajo ya que strptime() levanta un ArgumentError antes de que se alcance la validación.

validates :start_time, :format => { :with => /^([0-1][0-9]|[2][0-3]):([0-5][0-9])$|^/, 
    :message => "Invalid format." } 

puedo trabajar alrededor de esto poniendo una llamada condicional en start_time() como el ejemplo a continuación, pero que en realidad no funciona de manera satisfactoria por dos razones.

def start_time=(time) 
    if time =~ /^([0-1][0-9]|[2][0-3]):([0-5][0-9])$|^/ 
    date = start.midnight 
    self.start = add_string_time_to_date(date, time) 
    else 
    errors.add :start, "format invalid." 
    nil 
    end 
end 

First ActiveRecord parece no saber que el sistema ha fallado. Lo deduzco del hecho de que update_attributes() en el controlador regresa como si todo estuviera bien, aunque no fuera así. En segundo lugar, no se devuelve ningún comentario al usuario, por lo que la llamada a errors.add probablemente esté fuera de contexto. También es un poco feo.

La funcionalidad deseada es la de una validación estándar, por lo que si falla el usuario ve un error en el formulario al igual que con cualquier otro error de validación. En resumen, ¿cómo puedo lograr esta funcionalidad, y me estoy acercando a esto de la manera correcta?

¿Debo plantear una excepción específica para notificar a ActiveRecord de problemas y, de ser así, cuál es la mejor manera de hacerlo? Lo mejor es solo rescatar y usar el flash?

Respuesta

2

Debería dividir mejor la lógica de estos atributos.

  • Primero defina un attr_accessor para start_time (incluso si solo se guarda en la memoria).
  • A continuación, inicialice el valor en consecuencia.
  • Finalmente, establezca el atributo de inicio solo cuando se guarde el modelo.

Este sería el resultado:

class Shift < ActiveRecord::Base 
    attr_accessor :start_time 

    after_initialize :default_values 
    before_save :set_start 

    def add_string_time_to_date(date, string_time) 
    t = DateTime.strptime(string_time, "%H:%M") 
    DateTime.new(date.year, date.month, date.mday, t.hour, t.min) 
    end 

    private 

    def default_values 
    self.start_time = start.strftime("%H:%M") if start_time.nil? && start.present? 
    end 

    def set_start 
    if self.start_time.present? 
     date = start.midnight 
     self.start = add_string_time_to_date(date, time) 
    end 
    end 

end 
Cuestiones relacionadas