Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - Adding Custom Fields at runtime in ActiveRecord

You know how some bug trackers (and other software) allow you to add custom fields?

Typically this is done with a data structure that looks something like this:

  Items
----------
 ID | NAME | ITEM_TYPE_ID


 FieldDefinitions
---------------------------------------
 ID | ITEM_TYPE_ID | FIELD_NAME | FIELD_TYPE

 FieldValues
---------------------------------------
ID | FIELD_ID | ITEM_ID | VALUE

I'm trying to figure out the best way to approach this design in Rails. There will be many models which I want to allow extending simple properties.

When I retreive an Item I'd like it to include a hash of the addition field values that have been defined for that model.

like image 644
Ben Scheirman Avatar asked Feb 04 '10 14:02

Ben Scheirman


3 Answers

Something like...?

class Item < ActiveRecord::Base
  has_many :field_values
  has_many :field_definitions, :through => :field_values

  def custom_fields_hash
    cfh = {}
    self.field_values.each |fv|
      cfh[fv.field_definition] = fv
    end
    cfh
  end
end

class FieldValue < ActiveRecord::Base
  belongs_to :item
  belongs_to :field_definition
end

class FieldDefinition < ActiveRecord::Base
  has_many :field_values
  has_many :items, :through => field_values
end

Or, you could change

cfh[fv.field_definition] = fv

...to...

cfh[fv.field_definition.field_name] = fv.value
like image 65
Mike Tunnicliffe Avatar answered Nov 20 '22 00:11

Mike Tunnicliffe


Take a look at the Friendly ORM. It allows you to work with mysql without a schema. It was inspired by this blog post about how Friendfeed uses mysql to store schemaless data.

Friendly would replace ActiveRecord, although you can use ActiveRecord models next to Friendly models pretty easily.

like image 28
user94154 Avatar answered Nov 19 '22 23:11

user94154


If your intention is to have your FieldDefinition records belonging to different models (for example, a column item_id that points to either a SqueekyToyItem or a BalloonItem) then what you want is a polymorphic association.

It basically allows you to have an item_type column (beside your item_id column), which then specifies the actual type of item it points to.

There's a heading “Polymorphic associations” in the documentation for ActiveRecord::Associations::ClassMethods.

like image 1
Stéphan Kochen Avatar answered Nov 20 '22 00:11

Stéphan Kochen