Evaluar condiciones dinámicas


#1

Hola,

Tengo una aplicación en la cual necesito obtener siempre los objetos
en base a una condición dinámica, algo como esto:

class Recinto < ActiveRecord::Base
has_many :sesiones, :conditions => [fecha > ?, Time.now]
has_many :espectaulos, :through => sesiones
end

El problema de hacerlo así es que la condición se fija en el momento
de carga de la clase y luego no se vuelve a evaluar.

He estado mirando la opción with_scope, así como algunos plugins que
la usan pero siempre me encuentro con el mismo problema con las
condiciones dinámicas.

Supongo que siempre queda la alternativa de hacer un before_filter,
evaluar la condición y pasarla, pero me parece farragoso.

¿Cual sería la forma más DRY de hacer ésto?

Gracias y saludos.


#2

On 5/3/07, Eduardo Fernandez C. removed_email_address@domain.invalid
wrote:

El problema de hacerlo así es que la condición se fija en el momento
de carga de la clase y luego no se vuelve a evaluar.

He estado mirando la opción with_scope, así como algunos plugins que
la usan pero siempre me encuentro con el mismo problema con las
condiciones dinámicas.

Supongo que siempre queda la alternativa de hacer un before_filter,
evaluar la condición y pasarla, pero me parece farragoso.

¿Cual sería la forma más DRY de hacer ésto?

Yo haría algo
así:
class Recinto < ActiveRecord::Base
has_many :sesiones
has_many :espectaulos, :through => :sesiones

def sesiones_futuras
sesiones.find(:all, :conditions => [“fecha > ?”, Time.now])
end
end

También tendrías que hacer algo parecido para los espectáculos, claro.


Sergio Gil Pérez de la Manga
e-mail > removed_email_address@domain.invalid
blog > http://www.lacoctelera.com/porras


#3

On 5/3/07, Sergio Gil Pérez de la Manga removed_email_address@domain.invalid wrote:

On 5/3/07, Eduardo Fernandez C. removed_email_address@domain.invalid wrote:

Hola,

Tengo una aplicación en la cual necesito obtener siempre los objetos
en base a una condición dinámica, algo como esto:

class Recinto < ActiveRecord::Base
has_many :sesiones, :conditions => [fecha > ?, Time.now]
has_many :espectaulos, :through => sesiones
end

Eduardo, qué pasa si hacés esto:

class Recinto < ActiveRecord::Base
has_many :sesiones, :conditions => 'fecha > ‘#{Time.now.to_s(:db)}’
has_many :espectaulos, :through => sesiones
end

Ojo, que las comillas son simples, justamente porque no querés que se
evalúe en la definición de la clase. Estoy casi seguro que una vez
anduvo…

Sergio, creo que lo que decís se podría hacer
así:
class Sesion < AR::Base
class << self
def futuras
find(:all, :conditions => [“fecha > ?”, Time.now])
end
end
end

class Recinto < AR::Base
has_many :sesiones
end

y luego:

recinto = Recinto.find(:first)
recinto.sesiones.futuras

Perdón que no lo puedo probar ahora :frowning:

Pero también estoy casi seguro de que anda y es lindo :slight_smile:

Saludos!


#4

On May 3, 2007, at 6:41 PM, Damian J. wrote:

has_many :espectaulos, :through => sesiones
end

Eduardo, qué pasa si hacés esto:

class Recinto < ActiveRecord::Base
has_many :sesiones, :conditions => 'fecha > ‘#{Time.now.to_s(:db)}’

El problema de esta aproximacion es que esa linea invoca un metodo de
clase que se ejecuta al interpretar la definicion, por tanto una sola
vez en la vida de la clase.

Debido a ello, la definicion de la relacion se queda con ese valor
“cacheado” ya que se interpola la cadena al ejecutarse el metodo.
Esto en desarrollo puede que no se vea porque la clase se recarga por
request, pero en produccion no funcionaria.

– fxn


#5

Damian,

Efectivamente Xavier tiene razón, son métodos de clase que se
mantienen durante la vida de la clase, con lo cual sigo teniendo el
problema.

El primer ejemplo que dio Sergio al ser un método de intancia sí
funciona, creo que es la mejor forma.

Gracias 1024.


#6

On 5/3/07, Xavier N. removed_email_address@domain.invalid wrote:

Esto en desarrollo puede que no se vea porque la clase se recarga por
request, pero en produccion no funcionaria.

Xavier, justamente por eso puse las comillas simples, no las dobles.
Lo que me pasó es que lo probé una vez y me anduvo, como si el valor
de :conditions fuese evaluado al construir la consulta.

De todas maneras es un hack bastante feo :slight_smile:


#7

On May 3, 2007, at 8:37 PM, Damian J. wrote:

Debido a ello, la definicion de la relacion se queda con ese valor
“cacheado” ya que se interpola la cadena al ejecutarse el metodo.
Esto en desarrollo puede que no se vea porque la clase se recarga por
request, pero en produccion no funcionaria.

Xavier, justamente por eso puse las comillas simples, no las dobles.
Lo que me pasó es que lo probé una vez y me anduvo, como si el valor
de :conditions fuese evaluado al construir la consulta.

Ah, ok, como en general la evaluacion de codigo con eval es inusual,
la cadena no estaba cerrada, y el SQL de dentro tenia comillas
simples, pense que la de afuera era en realidad doble.


#8

On 5/3/07, Damian J. removed_email_address@domain.invalid wrote:

has_many :sesiones
end

y luego:

recinto = Recinto.find(:first)
recinto.sesiones.futuras

Perdón que no lo puedo probar ahora :frowning:

Pero también estoy casi seguro de que anda y es lindo :slight_smile:

Sí, o también (ojo que tampoco lo he probado ahora mismo para este
ejemplo concreto):

has_many :sesiones do
def futuras
find(:all, :conditions => [“fecha > ?”, Time.now])
end
end

y luego, igual:

recinto = Recinto.find(:first)
recinto.sesiones.futuras

La verdad es que hay varias formas de hacerlo y elegí la más fea =xD
En realidad todas vienen a ser lo mismo, y funcionan (deberían, vaya).


Sergio Gil Pérez de la Manga
e-mail > removed_email_address@domain.invalid
blog > http://www.lacoctelera.com/porras