refactoring thick models? what approach do you use?

Hi,

What practice does Rails suggest for refactoring thick models? If you split out methods from a model class where would you typically put them? Which rails technique would you use to access them, such as (a) mix-in's, (b) call them in their own separate class, e.g. modelname_tools.method, or perhaps one of the (c) rails meta-programming means of loading up extra methods (class methods or instance methods) into a class.

For example I have a bank "transaction" model for which there are now a few Class methods such as "self.auto_categorise", so I would assume splitting these out into a separate file. So this case which file to put them into, which directory to house it, and if the methods "added" back into the model which approach to do this?

thanks in advance

A thick model is okay, depending on why its thick... there may be another model(s) hiding in that code which could be factored out into a new class or classes.

For common model methods, I started with a simple module that was included by the classes making use of those methods.

As the number of those methods grew and became more pervasive in their use, I introduced a "GenericModel" to sit between my model classes and ActiveRecord::Base, the GenericModel class is where all the really common functionality resides now (and specific classes can override if necessary).

I did the same thing with my controllers as well, using the magic of constantize which lets my GenericController class contain code like:

params[:controller].singularize.camelcase.constantize.paginate blah blah blah

and

params[:controller].singularize.camelcase.constantize.new

to handle requests for almost all the actions of all my controllers, giving me one place to put all my rescues and standard "where do I go from here?" logic.

rough outline:

a lot of methods will most likely go into the helpers related to the controller (most of the things related to the views) some go into the model (most things related to database activity) application.rb for small things needed in several controllers

everything that doesn't fit in those wold get it's own lib in lib folder

splitting the controller would be another way to thin it out, rethink your RESTfull and CRUD design

DHH's keynote at railsconf europe outlined one possible way. Split out related bits of functionality into modules, eg your structure could be

person.rb person/notifications.rb person/something_else.rb.

and then Person includes those modules

Fred

Rick Olsen has a neat way of doing this: http://pastie.org/pastes/200292.

RSL

thanks

Russell/Fred - Your suggested way (or Rick Olsen's specifically) looks good. I was wondering if there is any reason it could be more dynamic however, like automatically include (or "require_dependency") for every file it (the model) sees under it's own directly? i.e. then you could place such discovery & include code inside ActiveRecord::Base including some mechanism (not sure what it would be offhand) that ensures that whenever a new active record class is loaded, the equivalent of a "require_dependency" is in place for each file under the model's directly.

BTW - Anyone know why I can't see "require_dependency" in the Rails API or Ruby API?

I’m gonna have to say that as alluring and leet and fun as automagically loading things without being called can be, it’s a hell of a lot easier on fellow programmers when you explicitly call/load code. When some method loaded/created in a non-standard location starts breaking it can be a pain figuring out where. This isn’t the worst example of doing this but it’s a habit I’m reluctant to endorse. YMMV.

RSL

yeah, you're probably right - I'm just thinking of the pain trying to read through rails plugins code where with all the metaprogramming concepts you kind of have to be a brain surgeon to see how everything really fits together..