4Trabes Historias de una empresa en 100 metros cuadrados

El blog de Trabe Soluciones

Si Rails no es multihilo entonces...

|

…podemos olvidarnos de algunas costumbres adquiridas con otras plataformas (léase J2EE o .NET) y aprovechar ciertas construcciones de Ruby que en un entorno multihilo sería problemático usar libremente. ¿A qué me refiero?, a variables de clase.

Las amigables variables de clase almacenan valores compartidos por todas las instancias de dicha clase, y a estas alturas todos deberíamos saber que si más de un hilo puede leer/modificar una de estas variables, tenemos que gestionar la concurrencia. No obstante, el caso de Rails es diferente. Podemos asegurar que cada instancia de nuestro servidor (normalmente un mongrel) sólo va a ejecutar un hilo por cada petición y por tanto podemos utilizar las variables de clase impunemente.

Supongamos, como ejemplo, una página que muestra varios valores monetarios sujetos a tipo de cambio. Supongamos el siguiente código que gestiona ésto (sin entrar a discutir si es adecuado o 100% correcto, que no lo es, ya lo sé, pero para ilustrar la idea vale).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class Currency
  TYPES = %w(euro dollar)

  attr_accessor :value

  def initialize(value)
    self.value = value
  end

  def to
    Exchange.new self
  end

  alias :in :to
end

class Dollar < Currency
  def to_s
    "#{value}$"
  end
end

class Euro < Currency
  def to_s
    "#{value}€"
  end
end

class Exchange
  cattr_accessor :rates

  def initialize(currency)
    @currency = currency
  end

  for currency in Currency::TYPES
    class_eval %{
      def #{currency}        
        rate = self.class.rates[:#{currency}][@currency.class.name.downcase]
        #{currency.classify}.new @currency.value * rate
      end
      
      alias :#{currency.pluralize} :#{currency}
    }
  end
end

class Fixnum
  for currency in Currency::TYPES
    class_eval %{
      def #{currency}
        #{currency.capitalize}.new self
      end
       
      alias :#{currency.pluralize} :#{currency}
    }
  end
end

De tal modo que, para cada petición sólo es necesario fijar una vez las tipos de cambio, usando para ello un before_filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def exchange_rates_set_before_filter

  # ... Lógica real para obtener los tipos de cambio ...

  Exchange.rates = HashWithIndifferentAccess.new({
    :dollar => {
      :dollar => 1,
      :euro => 1.49
    },
    :euro => {
      :euro => 1,
      :dollar => 0.67
    }
})

Y así poder escribir en nuestras vistas cosas sencillas y elegantes como:

1
2
1.dollar.in.euros #=> 0.67€
2.euros.in.dollars #=> 2.98$


Lo sentimos, pero los comentarios están cerrados