Jakub Troszok
Jakub Troszok

Reputation: 103863

Alternatives to use polymorphism in Ruby on Rails

I'm currently writing some intranet web application where people could submit to admins requests for adding different resources. The example requests would be:

I was thinking about having just one model UserRequests with the reference to the sender and two optional attributes one would be reference_id that would refefrence to other tables (for example the Program that he wants installed) and another would be used for free type fields like email alias or quota.

So my problem is that based on the type of the request the model should contain either:

Based on the type of the request the given action should be taken - probably email alias could be added from rails but the application on users computer will be installed by hand.

Does anyone had similar problem? Do you think using polymorphism for this kind of stuff is a good idea? Do you have any suggestions on how to organize data in the tables?

Upvotes: 8

Views: 4119

Answers (2)

Ian Terrell
Ian Terrell

Reputation: 10876

Single Table Inheritance! This way you can have each type of request have custom validations, while still having every request live in the same table.

class CreateUserRequests < ActiveRecord::Migration
  def self.up
    create_table :user_requests do |t|
      t.string :string_data, :type
      t.integer :user_id, :integer_data
      t.timestamps
    end
  end
  def self.down
    drop_table :user_requests
  end
end


class UserRequest < ActiveRecord::Base
  belongs_to :user
end

class EmailAliasRequest < UserRequest
  validates_presence_of :string_data
  validates_format_of :string_data, :with => EMAIL_REGEX
end

class ProgramInstallRequest < UserRequest
  belongs_to :program, :class_name => "Program", :foreign_key => "integer_data"
  validates_presence_of :integer_data
end

class QuotaIncreaseRequest < UserRequest
  validates_presence_of :string_data
  validates_inclusion_of :string_data, :in => %w( 1GB 5GB 10GB 15GB )
end

And of course, alias your string_data and integer_data to email or whatnot to make your other code have a little more meaning. Let the model be the little black box that hides it all away.

Upvotes: 9

John Topley
John Topley

Reputation: 115432

I would use polymorphic associations, which let a model belong to more than one other model using a single association. Something like this:

class AdminRequest < ActiveRecord::Base
  belongs_to :user
  belongs_to :requestable, :polymorphic => true
end

class EmailAlias < ActiveRecord::Base
  has_many :admin_requests, :as => :requestable
end

class ProgramInstall < ActiveRecord::Base
  has_many :admin_requests, :as => :requestable
end

class QuotaIncrease < ActiveRecord::Base
  has_many :admin_requests, :as => :requestable
end
  • As ever, Ryan Bates has an excellent Railscast on the subject.

Upvotes: 2

Related Questions