Sigh, por que no haces lo de poner el include/extend en cada modelo?

2009/10/3 Martin Aceto <[email protected]>:
>
>
> 2009/10/3 Nicolás Sanguinetti <[email protected]>
>>
>> 2009/10/3 Martin Aceto <[email protected]>:
>> >
>> >
>> >> 2009/10/3 Martin Aceto <[email protected]>:
>> >> >
>> >> >
>> >> > 2009/10/3 Nelson Fernandez <[email protected]>
>> >> >>
>> >> >> 2009/10/3 Martin Aceto <[email protected]>
>> >> >>>
>> >> >>> 2009/10/3 Nelson Fernandez <[email protected]>
>> >> >>>>
>> >> >>>> Martin !
>> >> >>>>
>> >> >>>> 2009/10/2 Martin Aceto <[email protected]>
>> >> >>>>>
>> >> >>>>> Hola, como estan
>> >> >>>>>
>> >> >>>>> estoy tratando de extender activerecord para poder sacar de un
>> >> >>>>> modelo
>> >> >>>>> logica que no pertenece a ese modelo sino que engloba varios
>> >> >>>>> modelos, logica
>> >> >>>>> de negocio bastante complicada que desearia separar.
>> >> >>>>>
>> >> >>>>> Me encuentro con la pregunta de cual es la forma correcta de
>> >> >>>>> hacerlo
>> >> >>>>> ?
>> >> >>>>>
>> >> >>>>> Lo que pense fue crear un archivo en /lib y dentro definir esos
>> >> >>>>> metodos
>> >> >>>>> que necesito, este ejemplo de abajo es correcto ? o estoy
>> >> >>>>> equivocado
>> >> >>>>> en mi
>> >> >>>>> concepto ?
>> >> >>>>>
>> >> >>>>> module Test
>> >> >>>>>   module ClassMethods
>> >> >>>>>     def test
>> >> >>>>>       puts "Test"
>> >> >>>>>     end
>> >> >>>>>   end
>> >> >>>>> end
>> >> >>>>>
>> >> >>>>> ActiveRecord::Base.send(:extend, Test::ClassMethods)
>> >> >>>>
>> >> >>>>
>> >> >>>> Comparto con Emanuel de usar la menos magia posible .. quizás otra
>> >> >>>> solución simple sea usar mixins [1] ?.
>> >> >>>>
>> >> >>>> [1] http://www.rubycentral.com/pickaxe/tut_modules.html#S2
>> >> >>>>
>> >> >>>>
>> >> >>>> --
>> >> >>>> :: nelson ::
>> >> >>>> [ artesano de software & software craftsman ]
>> >> >>>> http://netflux.com.ar
>> >> >>>>
>> >> >>>>
>> >> >>>>
>> >> >>>
>> >> >>> Leí el enlace que mandaste Nelson, si es mas simple, esta bueno.
>> >> >>> Pero
>> >> >>> quiero extender ActiveRecord para poder tener esos metodos en todas
>> >> >>> las
>> >> >>> clases, estoy intentando hacer esto como dijo Emmanuel
>> >> >>>
>> >> >>> module Test
>> >> >>>
>> >> >>>   module ClassMethods
>> >> >>>
>> >> >>>     def test
>> >> >>>       puts "Test"
>> >> >>>     end
>> >> >>>
>> >> >>>   end
>> >> >>>
>> >> >>> end
>> >> >>>
>> >> >>> ActiveRecord::Base.extend, Test::ClassMethods
>> >> >>> ActiveRecord::Base.class_eval do
>> >> >>>   include Test::InstanceMethods
>> >> >>> end
>> >> >>>
>> >> >>> pero no me funciona, y no entiendo porque, pero si incluyo
>> >> >>> directamente
>> >> >>> en una clase de esta manera
>> >> >>>
>> >> >>
>> >> >>
>> >> >> "extend" es para agregar los métodos de un modulo a una "instancia",
>> >> >> no
>> >> >> a
>> >> >> una clase.
>> >> >> Lo que está haciendo "ActiveRecord::Base.extend Test::ClassMethods"
>> >> >> es
>> >> >> extender el objeto que implementa Class... en el caso práctico estás
>> >> >> agregando métodos de clase, es decir que lo que va a funcionar es
>> >> >>
>> >> >> ActiveRecord::Base.test
>> >> >> o
>> >> >> MyModelo.test
>> >> >>
>> >> >> que no es lo que estas buscando, creo... sino que las instancias de
>> >> >> ActiveRecord tengan tus nuevos métodos.
>> >> >>
>> >> >> Para mí la forma más simple y clara nuevamente es usar mixins y de
>> >> >> esa
>> >> >> forma queda muy claro que modelos van a tener esa funcionalidad
>> >> >> agregada.
>> >> >>
>> >> >>
>> >> >>
>> >> >> PD: Te recomiendo ver este video donde Dave Thomas explica el modelo
>> >> >> de
>> >> >> objetos de Ruby
>> >> >>
>> >> >> http://scotland-on-rails.s3.amazonaws.com/2A04_DaveThomas-SOR.mp4
>> >> >>
>> >> >> y este muy gracioso cuando Joe OBrian quiere usar metaprograming a
>> >> >> toda
>> >> >> costa ;)
>> >> >>
>> >> >>
>> >> >>
>> >> >> http://scotland-on-rails.s3.amazonaws.com/2A08_JoeOBrianJimWeirich-SOR.mp4
>> >> >>
>> >> >>
>> >> >
>> >> > Nelson, lo que estoy intentando hacer, como vos dijiste,  es extender
>> >> > el
>> >> > objeto que implementa Class y poder hacer
>> >> >
>> >> > ActiveRecord::Base.test
>> >> > o
>> >> > MyModelo.test
>> >> > pero no se porque no me funciona.
>> >> >
>> >> > Gracias
>> >> >
>> >>
>> > 2009/10/3 Nicolás Sanguinetti <[email protected]>
>> >
>> > Primero (y hago top posting porque recien me levante, tengo sueño, y
>> > soy re heavy re jodido :P) lo que decía Emmanuel sobre "clases
>> > específicas" no es que si lo vas a usar en *una sola clase*, sino en
>> > *algunas* clases especificas. Ponele que tenés una aplicación chica,
>> > con no sé, 10 modelos.
>> >
>> > Si vos querés extraer una funcionalidad a algo que se comparte entre 4
>> > o 5 de ellos, hacer ActiveRecord::Base.extend(MyAwesomeMixin) es
>> > chancho. Le
>> > estás encajando métodos a 5 o 6 modelos que no tienen nada
>> >>
>> >> que ver con eso.
>> >>
>> >> Entonces lo prolijo sería hacer el "include" o "extend" en cada uno de
>> >> los 4 o 5 modelos que necesitan MyAwesomeMixin.
>> >>
>> >> class User < AR::B
>> >>  include Foo
>> >> end
>> >>
>> >> class Thing < AR::B
>> >>  include Foo
>> >> end
>> >>
>> >> etc.
>> >>
>> >> Segundo, si vos lo que querés es agregar métodos de clase compartidos
>> >> entre varios modelos (por ejemplo, finders, métodos de search, etc),
>> >> lo que querés hacer es extend, sí.
>> >>
>> >> class User < AR::B
>> >>  extend FooBar
>> >> end
>> >>
>> >> Si estás haciendo esto (como entiendo de tu primer post) y no
>> >> funciona, entonces va a ser mejor que hagas un paste con código "más
>> >> de verdad" para entender dónde está el problema. Por que lo que vos
>> >> pegaste arriba, tiene que andar.
>> >>
>> >> (Ojo al gol, si vos ponés un 'puts' en un modelo, el output lo vas a
>> >> ver en el mismo output que tu server si usas mongrel/thin/etc, o no lo
>> >> vás a ver nada si usás passenger—capaz que el problema es ese? Probá
>> >> poner Rails.logger.info("---------> test") y fijarte si no aparece en
>> >> el log)
>> >>
>> >> -f
>> >
>> >
>> > Hola Nicolas, entiendo lo que decis de que extender ActiveRecord para
>> > todos
>> > los modelos cuando solo la mitad o menos usaran esos metodos, es chanco,
>> > por
>> > lo cual voy a utilizar include o extend en los modelos que necesito esos
>> > metodos especificos.
>> >
>> > Pero de todas estas preguntas y respuestas me quede con la intriga de
>> > como
>> > hacer para extender ActiveRecord para agregar, finders, metodos de
>> > search,
>> > etc... para toda la aplicación, por eso les comente que no me funcionaba
>> > esto
>> >
>> >
>> > module Test
>> >   module ClassMethods
>> >     def test
>> >       puts "Test"
>> >     end
>> >   end
>> > end
>> >
>> > ActiveRecord::Base.extend, Test::ClassMethods
>> > ActiveRecord::Base.class_eval do
>> >   include Test::InstanceMethods
>> > end
>> >
>> > (todo mi codigo se reduce a esto) solo una simple prueba
>> >
>> > por lo que yo entendi con ese codigo de arriba podria hacer en una
>> > consola
>> > para cualquier modelo del app, como por ejemplo User
>> >
>> > User.test
>> >
>> > y me daria el texto "text".
>> > Esto sin hacer ningún include o extend dentro de User, no es así ?
>>
>> Ah, pará, vos dijiste que pusiste el código en lib, no?
>>
>> En dónde estás haciendo los llamados a extend? Si es desde el mismo
>> archivo, tenés que, en algún lado, requerir ese archivo. Rails no
>> requiere todos los archivos, los requiere a medida que se necesitan, y
>> el mecanismo para saber eso es según nombres de constantes.
>>
>> Si vos pedís Foo en algún lado se va a fijar por app/models/foo.rb,
>> lib/foo.rb, vendor/gems/*/lib/foo.rb, vendor/plugins/*/lib/foo.rb.
>> (Creo que en ese orden, pero tampoco es importante).
>>
>> El tema es que si vos directamente llamás al método en el modelo, sin
>> haber requerido antes el archivo, no va a andar :)
>>
>> Si lo vás a extender explicitamente en los modelos, al hacer
>>
>> class User
>>  extend MyAwesomeMixin
>> end
>>
>> estás referenciando la constante, y por ende haciendo que rails
>> requiera el archivo (en cuyo caso va a funcionar).
>>
>> Pero si querés que lo meta en todos los archivos, entonces el
>> ActiveRecord::Base.extend(MyAwesomeMixin) tendrías que ponerlo en un
>> initializer, en config/initializers/my_awesome_mixin.rb -- eso se
>> asegura de que todos los modelos tengan esos métodos cuando inicia el
>> framework.
>>
>> Saludos,
>> -f
>>
>>
>
> Ahi funciono, me faltaba saber eso, no estaba requeriendo el archivo y por
> eso no lo tenia disponible en todos los modelos, ahora me quedo
>
> config/initializers/extend_ar.rb
>
> ActiveRecord::Base.extend(Test::ClassMethods)
> ActiveRecord::Base.class_eval do
>   include Test::InstanceMethods
> end
>
> y en lib/test.rb
>
> module Test
>    module ClassMethods
>      def test
>        puts "Test"
>      end
>    end
>
>   module InstanceMethods
>   end
> end
>
> y funciona perfecto !
>
> Tenes idea donde esta en la doc de rails esto de que se tiene que requerir
> el archivo para que haga el extend  ? tendria que leerla.
>
> Gracias Nicolas
>
> _______________________________________________
> Ruby mailing list
> [email protected]
> http://lista.rubyargentina.com.ar/listinfo.cgi/ruby-rubyargentina.com.ar
>
>
_______________________________________________
Ruby mailing list
[email protected]
http://lista.rubyargentina.com.ar/listinfo.cgi/ruby-rubyargentina.com.ar

Responder a