Is there such a thing? I have some duplicate methods in my models, can I place them somewhere and call them in to my models, thus keeping DRY?
on 2006-02-21 23:01
on 2006-02-21 23:13
Put them in a superclass? Tony
on 2006-02-21 23:40
Hello James, 2006/2/21, James Whittaker <email@example.com>: > Is there such a thing? Put them in a module, and include the module in your models. The module should go into lib/, and the file name should reflect Rails conventions so that the simple include will be all you need. Hope that helps !
on 2006-02-22 07:01
On Feb 21, 2006, at 2:01 PM, James Whittaker wrote: > Is there such a thing? > > I have some duplicate methods in my models, can I place them somewhere > and call them in to my models, thus keeping DRY? This is what inheritance is for. -- Eric Hodel - firstname.lastname@example.org - http://segment7.net This implementation is HODEL-HASH-9600 compliant http://trackmap.robotcoop.com
on 2006-02-22 07:27
Someone tell Eric about modules :-)
on 2006-02-22 08:34
Eric Hodel wrote: > On Feb 21, 2006, at 2:01 PM, James Whittaker wrote: > >> Is there such a thing? >> >> I have some duplicate methods in my models, can I place them somewhere >> and call them in to my models, thus keeping DRY? > > > This is what inheritance is for. > Yes, really... I'm still pretty new to rails but this advice of "put your common model behavior in a mixin" while models have to inherit from the framework's ORM solution just seems absolutely bass-ackwards! Some day I will learn enough rails/ruby to make ActiveRecord (or Og) a mixin and have my simple POROs (plain ol ruby objects) left totally untouched by the framework. :-) b
on 2006-02-22 09:17
Another option in an intermediate class: modela < basemodel < activerecord. I think Dave Thomas blogged about doing just such a thing in an import scenario. Jack
on 2006-02-23 00:52
On Feb 21, 2006, at 10:27 PM, Andy wrote: > Someone tell Eric about modules :-) You must like overly-complex overly-obfuscated code then. You can't easily add validations with modules, you can with inheritance. You can't easily add relationships with modules, you can with inheritance. You can't easily override base class methods via modules, you can with inheritance. I've been writing Ruby a long time, and I've found that use of included, extended, append_features and alias are best used when you need to be clever and can't use features like inheritance to accomplish your goals. After all, Ruby is an OO language, so if you treat it as such it will help you accomplish your goals without getting in your way. When you are frequently use append_features or extended or included you add complexity you don't need which ultimately leads to confusion when you need to figure out what you did last week, last month or last year. You're also violating DRY when you use the module and class callbacks and alias instead of inheritance because the language built inheritance in for you. There's no need for you to go behind the language's back. Compare inheritance: class Mine < Theirs def my_method(some_arg) super(some_arg + 1) end end Simple, elegant, expressive and short, only 5 total lines to override my_method to provide custom behavior. With modules: module AddOne def self.included(klass) klass.class_eval do alias_method :my_method_without_add, :my_method alias_method :my_method, :my_method_with_add end end def my_method_with_add(some_arg) my_method_without_add(some_arg + 1) end end class Theirs include AddOne end This is much longer, 14 lines, and much more difficult to figure out if you want to change the behavior at a future date. This also raises many questions: What classes can AddOne be applied to? By looking at class Theirs, what behavior can I depend upon when calling my_method? What do I do if I want to extend the behavior of my_method twice? Does order of include matter? If I call include from the same file as the module I've pushed the dependencies down to the order of require. (This is especially bad, order of requires should not be important to correct functioning of your code, they should just enumerate the transitive closure for your dependencies.) Unlike Comparable or Enumerable which have well-defined and unchanging features, custom modules are likely to incorporate a large set of functionality so you lose information about the functionality of your program because either: You call include from your only class definition so don't know what include will ultimately do. You call include from the module definition file, so don't know that include was called at all. Now you have to look in two places to determine what a given method will do, but you may not even know to look. Refactoring is harder because your dependencies are spread out too much. I'd rather reserve my fancy Module and Class callbacks for the places I really need them, like MuffDaddy. -- Eric Hodel - email@example.com - http://segment7.net This implementation is HODEL-HASH-9600 compliant http://trackmap.robotcoop.com
on 2006-02-23 01:03
Eric Hodel wrote: > I'd rather reserve my fancy Module and Class callbacks for the places > I really need them, like MuffDaddy. OK, I'll ask: what does MuffDaddy do? Joe
on 2006-02-23 07:19
Well stated. So, how do you feel about models inheriting from ActiveRecord rather than having persistence mixed-in? b
on 2006-02-23 15:33
Eric Hodel wrote: > On Feb 21, 2006, at 2:01 PM, James Whittaker wrote: > >> Is there such a thing? >> >> I have some duplicate methods in my models, can I place them somewhere >> and call them in to my models, thus keeping DRY? > > This is what inheritance is for. Hmmmm. I'd suggest this is not what inheritance is *for*. Inheritance is a necessary mechanism for polymorphism is some languages, and a mechanism for varying behaviour. If I need to be able to not care whether its a Person or Company, all I care about is that it has methods for manipulating the address, I can have an Addressable base class and hey presto, polymorphism. I can also vary the behaviour in the subclasses (as you point out in a later post). In removing duplicated code in a class, you can either use "Extract Superclass" or just plain old "Extract Class" and which way I go very much depends on exactly what those duplicate methods are. Inheritance may be the way to go here, if it looks like both those models may need to vary the behaviour (no need to worry about the polymorphic angle thanks to duck typing! :). If, however, the methods are orthogonal to the Model classes, it could be more sensible to pull them out into a class of their own, and aggregate as necessary, or as a Module, and mixin as necessary. I'm not saying you're wrong, Eric, just that you're not necessarily right :-) James, are you at liberty to give us a flavour of the nature of the duplication ? A.
on 2006-02-24 06:42
On Feb 22, 2006, at 4:03 PM, Joe wrote: > Eric Hodel wrote: >> I'd rather reserve my fancy Module and Class callbacks for the places >> I really need them, like MuffDaddy. > > OK, I'll ask: what does MuffDaddy do? Its the ultimate rapper. http://blog.zenspider.com/archives/2005/02/muffdad... -- Eric Hodel - firstname.lastname@example.org - http://segment7.net This implementation is HODEL-HASH-9600 compliant http://trackmap.robotcoop.com