miércoles, 3 de junio de 2009

Definición de named_scopes dependientes del tiempo actual

Si tenemos una clase ActiveRecord como la siguiente:

class Post < ActiveRecord::Base
named_scope :test, :conditions => ['updated_at < ?', Time.now]
end

En modo development funciona sin problemas, sin embargo en modo production la consulta que se genera no es la esperada.

Al arrancar rails en modo production se cachean las clases, al cargar este modelo en concreto se evalúa Time.now haciendo que para todas las consultas se coja como fecha la hora en la que se ha cargado el modelo.

El descrito anteriormente no es el comportamiento que esperaríamos al definir el named_scope, sino que debería obtener la fecha y hora actual para cada consulta, no en la definición.

Revisando la definición de los named_scopes nos encontramos lo siguiente:

def named_scope(name, options = {}, &block)
name = name.to_sym
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
options
when Proc
options.call(*args)
end, &block)
end
(class << self; self end).instance_eval do
define_method name do |*args|
scopes[name].call(self, *args)
end
end
end


En nuestro caso pasamos un hash como opciones, por lo que efectivamente se evaluará el Time.now solo en la definición de dicho hash.

Si en lugar de eso definimos un objeto de tipo Proc se evaluará cada vez.

Por lo tanto para arreglar el comportamiento del primer ejemplo deberíamos escribirlo como:

class Post < ActiveRecord::Base
named_scope :test, lambda{{:conditions => ['updated_at < ?', Time.now]}}
end

0 comentarios: