Sharing Code Between ActiveRecord Models

I was frustrated with the amount of duplicated code sprinkled in my models that are using the attachment_fu plugin to deal with file uploads. It’s not like I need to write a plugin or anything fancy – I just want to be a little more DRY.

So, how does one simply share code between ActiveRecord models? It’s actually quite easy.

First, drop some code into a module in a .rb file in your lib directory. For example:

# lib/attachment_fu_extensions.rb

module AttachmentFuExtensions
  # include some standard attachment_fu stuff
  def self.included(klass)
    klass.send :validates_as_attachment
    klass.send :validates_uniqueness_of, :filename
    klass.send :validates_presence_of, :user_id
    klass.send :attr_protected, :id, :parent_id, :user_id, :created_at, :updated_at

  # upload into a single directory (e.g. public/uploads) instead of subdirectories based on the id
  def full_filename(thumbnail = nil)
    file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
    File.join(RAILS_ROOT, file_system_path, thumbnail_name_for(thumbnail))

  # prevent users from uploading index files that would be served instead of the index template/action
  def validate
    errors.add("filename", "is invalid") if filename? && %w(index.html index.htm).include?(filename.downcase)


That code will automatically be loaded when your application starts, provided that the filename and module follow the standard Rails naming conventions.

Then, simply include the relevant module in the relevant models. For example:

# app/models/upload.rb

class Upload  :file_system, :path_prefix => 'public/uploads', :max_size => 10.megabytes
  include AttachmentFuExtensions

  # ...


That’s it. Extending ActiveRecord models and DRYing out your app is pretty easy, eh?

Update: Walter pointed out that I should put modules like this into lib/ instead of config/initializers/, so I’ve updated this post to reflect that. I’m not sure why that didn’t occur to me. He also told me about the trick for sharing calls to validates_as_attachment and so forth – I didn’t even know that was possible!

Published by

Trevor Turk

A chess-playing machine of the late 18th century, promoted as an automaton but later proved a hoax.

3 thoughts on “Sharing Code Between ActiveRecord Models”

  1. Shave some keystrokes:

    def self.included(klass)

    klass.class_eval do



    attr_accessor :fooferall



Comments are closed.