Splitting models into several smaller files in Rails

I was reading what Paul Barry had to say about splitting models into smaller files. It resonated with me a little – some of our models are approaching 1000 lines.But I felt the name ‘concerned_with’ did not fully / appropriately describe what is being done, and that there should be an easier way than having to specify every file to be required.So I ended up modifying the code to be a little easier to use.  If you place it in an initializer (i.e. in a file in your initializers directory), then you can specify in your model that you wish to require all the files from a subdirectory of the same name as the model.So if you model is called Customer, then the model file is customer.rb.  Now you can also have a subdirectory called customer that contains further files containing model code.In the original model class file you should add require_class_subdirectory to it, like this:

class Customer  require_class_subdirectory...end

This will cause all the files in the subdirectory to be required.In each file in the subdirectory you should open the model class like so:

class Customer  def something  # you can cut/paste code in from the main model file  end...end

The filenames you use don’t matter – in the above case it could be ‘something.rb’ for instance.So, to recap, your main class file customer.rb has ‘require_class_subdirectory’ added to it. You create a folder called ‘customer’ in your models directory, and place some .rb files in there. In each of those files you re-open the class (‘class Customer’) and place code there just as if you were writing into the main class file.This allows you to separate code according to function within a model, and to keep file sizes manageable.Here is the code to put in the initializer:

class << ActiveRecord::Base  def require_class_subdirectory    ActiveSupport::Dependencies.load_paths.select{|lp| lp =~ /app/models/}.each do |path|      Dir["#{path}/#{name.underscore}/*.rb"].each do |filename|        require_dependency "#{name.underscore}/#{File.basename(filename)}"      end    end  endend

Other approaches to this problem are possible. In particular it may be feasible to patch or hook the constant missing mechanism in rails to automatically load the files in the subdirectory, which would remove the need for the require_class_subdirectory line in your main model file.Finally, not even everyone thinks this is a problem that needs to be solved. My colleague who uses Aptana says it has a good outline mode that means it’s easier to work with one large file for a model than lots of smaller ones. In Textmate I find the smaller files easier.


One thought on “Splitting models into several smaller files in Rails

  1. […] Splitting models into several smaller files in Rails – I’m personally not convinced big models are a problem (I’d rather look in one large file than 6 small ones when tracing code). But if you disagree, here’s a solution for loading the pieces. […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s