Classy Inheritance

"You stay classy, inheritance" - Gibson

Installing

$ sudo gem install classy-inheritance

# in environment.rb add:
require "classy-inheritance" 

What

Classy Inheritance provides two methods:
  • depends_on allows you to define requisite objects.
  • can_be allows you to associate the various ActiveRecord models your polymorphic class can represent.

More functionality coming for optional relationships.

When using depends_on for both polymorphic and belongs_to relationships you will get the following added to your calling class. For instance if you have defined:

class User < ActiveRecord::Base
  depends_on :profile, :attrs => [:first_name, :last_name, :email]
end
You will get the following added to the User class:

class User < ActiveRecord::Base
  validates_presence_of :profile
  validates_associated :profile
  before_save :save_requisite_profile

  #...
  def save_requisite_profile
    self.profile.save
  end
end

Polymorphic


class Picture < ActiveRecord::Base
  depends_on :image, :attrs => [:filename, :height, :width], :as => "imageable" 
end

This will look for "imageable_type" and "imageable_id" on the images table add set them accordingly.

Polymorphic relationships have another feature. The above definition will add two methods to an image object:

  # automatically do :include => :image
  Picture.find_with_image

  # getters/setters for the attributes defined:
  @picture.height
  @picture.height = 100
  @picture.width
  @picture.width = 150
  @picture.filename
  @picture.filename = "/some/path/file.ext" 

  # return @image.imageable_type == 'Picture'
  @image.is_a_picture?

  # return Picture.find_with_image(@image.presentable_id)
  @image.as_a_picture

In addition, you can define the different types of models a polymorphic class can represent:

class Image < ActiveRecord::Base
  can_be :picture, :as => "imageable" 
end
This will give you the following methods:

  # return @image.imageable_type == 'Picture'
  @image.is_a_picture?

  # return Picture.find_with_image(@image.presentable_id)
  @image.as_a_picture

As you may have guessed, belongs_to will call can_be on the requisite class.

Note: If you are intending on calling Image.find (and you most likely are), it's best to manually add the can_be methods to Image. With class reloading in development mode, you won't get the methods from the Picture.depends_on call.

Belongs_To

You can define a standard belongs_to relationship:

class User < ActiveRecord::Base
  depends_on :profile, :attrs => [:first_name, :last_name, :email]
end

Similar to the polymorphic use, you will get pass-through methods for each attribute:


  @user.first_name
  @user.last_name
  @user.email
  @user.first_name=
  @user.last_name=
  @user.email=

This means you can use these attributes on your form and in your controller instead of having to worry about creating/updating a separate Profile model.

For the above example, you'll also get a "find_with_profile" class method that will do the :include => :profile addition to your find call for you.

Additional options

Option: prefix

class Bakery < ActiveRecord::Base
  depends_on :business, :attrs => [:name], :prefix => true
end

#Will give you:
@bakery.business_name

class Bakery < ActiveRecord::Base
  depends_on :business, :attrs => [:name], :prefix => "bakery" 
end

#Will give you:
@bakery.bakery_business_name
Option: postfix

Office.depends_on :billing_address, 
                  :attrs => [:line_one, :line_two, :city, :state_code, :postal_code],
                  :class_name => "Address", 
                  :foreign_key => "billing_address_id", 
                  :postfix => true
#Will give you:
@office.line_one_billing_address
@office.line_two_billing_address
@office.city_billing_address
@office.state_code_billing_address
@office.postal_code_billing_address

Office.depends_on :billing_address, 
                  :attrs => [:line_one, :line_two, :city, :state_code, :postal_code],
                  :class_name => "Address", 
                  :foreign_key => "billing_address_id", 
                  :postfix => "billing" 
#Will give you:
@office.line_one_billing
@office.line_two_billing
@office.city_billing
@office.state_code_billing
@office.postal_code_billing

Option: Standard Rails Options

Introduced with release 0.4.0, you can now add the Rails options provided for the type of association. If you use the :as option, the association is a :has_one, otherwise it's a :belongs_to association.

This means you can do the following:


class Document < ActiveRecord::Base
  depends_on :content, :attrs => [:name], 
             :as => :presentable, :dependent => :destroy
  ...
end

Options: validates_presence_if, validates_associated_if

You can now use these options to determine whether or not the validates_presence_of and validates_associated methods are called. By default, both methods are called. You can pass in true, false, string/symbol (for methods reference) or a Proc.

Github

http://github.com/stonean/classy-inheritance/tree/master

git://github.com/stonean/classy-inheritance.git

Contact

Please use the forum to ask questions and the issue tracker to report problems or submit a pull request.

License

This code is free to use under the terms of the MIT license.

Copyright (c) 2008 Andrew Stone

Also available in: HTML TXT