Soy desarrollador de PHP y en este momento estoy aprendiendo Rails (3) y, por supuesto, Ruby. I don't want to believe in magic y por eso trato de entender todo lo que pueda sobre las cosas que ocurren "detrás" de Rails. Lo que me pareció interesante son las llamadas a métodos como has_one
o belongs_to
en los modelos de ActiveRecord.¿Cómo funciona el método Rails como "has_one"?
Me trataron de reproducir esa, y venía con ingenua ejemplo: "¿Funcionará"
# has_one_test_1.rb
module Foo
class Base
def self.has_one
puts 'Will it work?'
end
end
end
class Model2 < Foo::Base
has_one
end
Sólo se ejecuta este archivo es la salida, como lo esperaba.
Mientras buscaba a través de la fuente de los rieles encontré la función responsable: def has_one(association_id, options = {}).
Como podría ser esto, porque obviamente es una instancia (?) Y no un método de clase, no debería funcionar.
Después de una cierta investigación me encontré con un ejemplo que podría ser una respuesta:
# has_one_test_2.rb
module Foo
module Bar
module Baz
def has_one stuff
puts "I CAN HAS #{stuff}?"
end
end
def self.included mod
mod.extend(Baz)
end
end
class Base
include Bar
end
end
class Model < Foo::Base
has_one 'CHEEZBURGER'
end
Ahora se ejecuta es la salida has_one_test_2.rb
archivo que he tengo cheezburger. Si lo entendí bien, lo primero que sucede es que la clase Base intenta incluir el módulo Bar. En el momento de esta inclusión, se invoca el método self.included
, que amplía el módulo Bar con el módulo Baz (y su método de instancia has_one
). Entonces, en esencia, el método has_one
está incluido (¿mezclado?) En la clase Base. Pero aún así, no lo entiendo del todo. Object#extend agrega el método del módulo, pero aún así, no estoy seguro de cómo reproducir este comportamiento utilizando extender. Así que mis preguntas son:
¿Qué pasó exactamente aquí. Quiero decir, ¿todavía no sé cómo se ha convertido un método en el método de clase? ¿Qué parte exactamente lo causó?
Esta posibilidad de hacer llamadas a este método (que se parece a la configuración) es realmente genial. ¿Hay una manera alternativa o más simple de lograr esto?