DynamicRecord Jonathan Linowes Parkerhill Technology Group NH Ruby Group, January 15, 2009 Extending Rails' ActiveRecord with  on-the-fly virtual attributes
Overview Built on Rails' ActiveRecord Dynamic attributes look and behave like standard ActiveRecord attributes Extends any attributes with meta properties Runtime add, modify, delete attributes A single AR model class can have multiple sets of dynamic attributes (e.g. per account)
Usage
acts_as_dynamic_record enables dynamic attributes in an ActiveRecord model supports active record magic including all flavors of find dynamic accessors (eg find_by_name)
Example class Submission < ActiveRecord::Base acts_as_dynamic_record --- Submission.dynamic_attributes.create :name => 'title' Submission.create :title => 'The title'  @s = Submission.find_by_title( 'The title' )
DynamicAttribute Attribute definition name storage value_type Meta description of attribute default_value null_allowed validators description value_options choices calculations
Storage types Active actual AR attributes (table columns) Dynamic add, modify, delete at runtime Delegation attributes in an association appear here e.g. @submission.user_email Attachment built-in association to an attachments table presently implemented with Paperclip
Value types string  text  integer  float  decimal  datetime  boolean
value options choices for selection lists notation: ['MA, 'ME', 'NH'] or [['Mass','MA'],['NewHamp','NH']] reports math: sum, average, min, max counting: count, %complete, completed type:  in-record: calculated on save (set of operands) summary: calculated on load (one operand, across records) datetime date only, time only, date and time
Validators null_allowed injected Rails validators [['numericality', { :only_integer => true }], ['inclusion', {:in => 1..5} ]] # => validates_numericality_of :attr_name, :only_integer => true # => validates_inclusion_of :attr_name, :in => 1..5
Associations also supports:  has_one, has_many, belongs_to has_one_of_many http://www.vaporbase.com/postings/has_one_of_many eager loading, nesting
Architecture
Architecture DynamicModel model  DynamicAttribute model  DynamicRow model  DynamicRecord  module
Storage schema tried EVA, didn't like it http://www.vaporbase.com/postings/Choosing_a_Schema_for_Dynamic_Records using fixed width rows
Setup
Migrations required tables for dynamic_models dynamic_attributes dynamic_rows
App-wide dynamic model Create in a migration create_table :things do |t| t.string :title end Thing.dynamic_model = DynamicModel.create :resource => :thing Thing.activate_attributes # add a dynamic attribute  Thing.dynamic_attributes.create :name => 'color', :value_type => 'string' Load in initializer Thing.dynamic_model = DynamicModel.find_by_name( 'thing' )
Multiple Dynamic Models Multiple sets of attributes for a given model A parent model maintains the dynamic attributes of a child one # each project has its own set of submission attributes project < ActiveRecord::Base has_many :submissions contains_dynamic_model :submission Add [child]_model_id to the parent model (aka belongs_to) Add dynamic_model_id to the child model
API
acts_as_dynamic_record class methods - configuration dynamic_model accessor dynamicable: names, descriptions, read_only dynamic_belongs_to dynamic_delegations_for class methods dynamic_attributes accessor dynamic_attributes_by_name find_with_dynamics
DynamicAttribute dynamic_storage, active_storage?, delegation_storage?, attachment_storage? resource, resource_class value_options: choices, choices_for_select, choices_for_edit, choices_to_s, choices_to_a report, math?, counting?, summary_report?, operands, operands=, operation, operation=, all_required, all_required?, validate_operands, calculate  datetime attachment_for confirmation_required?
contains_dynamic_model activate_dynamic_attributes  to create initial dattr's for a model initialize_dynamic_record_classes per request (not thread safe)
nested, eager associations To reference, load dynamic attributes in an association, nested Review < ActiveRecord::Base acts_as_dynamic_record belongs_to :submission dynamic_belongs_to :submission ... Review.find :all, :include => { :submission => :user }
Implementation
On the rails/ Off the rails Internal models also built on ActiveRecord Use of class variables @@dynamic_model Injects SQL translation between AR and connectors Tons of rspecs
“SQL injection” hackery re-process sql queries before they're issued solves: supports any (most) AR plugins supports all variants of AR#find including sort order, pagination, etc
Performance Issues of course! havent benchmarked, production env eager loading query caching key indexing etc.
Disclaimers Still in R&D, not a release API definition tuned for this presentation (i.e. dont use this as documentation) Learning curves developed while learning Ruby,  i'm not a database/sql guru, and  I dont mind breaking conventions to learn later that wasnt necessary... Not open sourced (yet), because not proven in production api still in flux need to pluginize (gemize) needs performance tuning not thread safe (uses class variables) it's still Rails 2.02 lack of time

DynamicRecord Presentation

  • 1.
    DynamicRecord Jonathan LinowesParkerhill Technology Group NH Ruby Group, January 15, 2009 Extending Rails' ActiveRecord with on-the-fly virtual attributes
  • 2.
    Overview Built onRails' ActiveRecord Dynamic attributes look and behave like standard ActiveRecord attributes Extends any attributes with meta properties Runtime add, modify, delete attributes A single AR model class can have multiple sets of dynamic attributes (e.g. per account)
  • 3.
  • 4.
    acts_as_dynamic_record enables dynamicattributes in an ActiveRecord model supports active record magic including all flavors of find dynamic accessors (eg find_by_name)
  • 5.
    Example class Submission< ActiveRecord::Base acts_as_dynamic_record --- Submission.dynamic_attributes.create :name => 'title' Submission.create :title => 'The title' @s = Submission.find_by_title( 'The title' )
  • 6.
    DynamicAttribute Attribute definitionname storage value_type Meta description of attribute default_value null_allowed validators description value_options choices calculations
  • 7.
    Storage types Activeactual AR attributes (table columns) Dynamic add, modify, delete at runtime Delegation attributes in an association appear here e.g. @submission.user_email Attachment built-in association to an attachments table presently implemented with Paperclip
  • 8.
    Value types string text integer float decimal datetime boolean
  • 9.
    value options choicesfor selection lists notation: ['MA, 'ME', 'NH'] or [['Mass','MA'],['NewHamp','NH']] reports math: sum, average, min, max counting: count, %complete, completed type: in-record: calculated on save (set of operands) summary: calculated on load (one operand, across records) datetime date only, time only, date and time
  • 10.
    Validators null_allowed injectedRails validators [['numericality', { :only_integer => true }], ['inclusion', {:in => 1..5} ]] # => validates_numericality_of :attr_name, :only_integer => true # => validates_inclusion_of :attr_name, :in => 1..5
  • 11.
    Associations also supports: has_one, has_many, belongs_to has_one_of_many http://www.vaporbase.com/postings/has_one_of_many eager loading, nesting
  • 12.
  • 13.
    Architecture DynamicModel model DynamicAttribute model DynamicRow model DynamicRecord module
  • 14.
    Storage schema triedEVA, didn't like it http://www.vaporbase.com/postings/Choosing_a_Schema_for_Dynamic_Records using fixed width rows
  • 15.
  • 16.
    Migrations required tablesfor dynamic_models dynamic_attributes dynamic_rows
  • 17.
    App-wide dynamic modelCreate in a migration create_table :things do |t| t.string :title end Thing.dynamic_model = DynamicModel.create :resource => :thing Thing.activate_attributes # add a dynamic attribute Thing.dynamic_attributes.create :name => 'color', :value_type => 'string' Load in initializer Thing.dynamic_model = DynamicModel.find_by_name( 'thing' )
  • 18.
    Multiple Dynamic ModelsMultiple sets of attributes for a given model A parent model maintains the dynamic attributes of a child one # each project has its own set of submission attributes project < ActiveRecord::Base has_many :submissions contains_dynamic_model :submission Add [child]_model_id to the parent model (aka belongs_to) Add dynamic_model_id to the child model
  • 19.
  • 20.
    acts_as_dynamic_record class methods- configuration dynamic_model accessor dynamicable: names, descriptions, read_only dynamic_belongs_to dynamic_delegations_for class methods dynamic_attributes accessor dynamic_attributes_by_name find_with_dynamics
  • 21.
    DynamicAttribute dynamic_storage, active_storage?,delegation_storage?, attachment_storage? resource, resource_class value_options: choices, choices_for_select, choices_for_edit, choices_to_s, choices_to_a report, math?, counting?, summary_report?, operands, operands=, operation, operation=, all_required, all_required?, validate_operands, calculate datetime attachment_for confirmation_required?
  • 22.
    contains_dynamic_model activate_dynamic_attributes to create initial dattr's for a model initialize_dynamic_record_classes per request (not thread safe)
  • 23.
    nested, eager associationsTo reference, load dynamic attributes in an association, nested Review < ActiveRecord::Base acts_as_dynamic_record belongs_to :submission dynamic_belongs_to :submission ... Review.find :all, :include => { :submission => :user }
  • 24.
  • 25.
    On the rails/Off the rails Internal models also built on ActiveRecord Use of class variables @@dynamic_model Injects SQL translation between AR and connectors Tons of rspecs
  • 26.
    “SQL injection” hackeryre-process sql queries before they're issued solves: supports any (most) AR plugins supports all variants of AR#find including sort order, pagination, etc
  • 27.
    Performance Issues ofcourse! havent benchmarked, production env eager loading query caching key indexing etc.
  • 28.
    Disclaimers Still inR&D, not a release API definition tuned for this presentation (i.e. dont use this as documentation) Learning curves developed while learning Ruby, i'm not a database/sql guru, and I dont mind breaking conventions to learn later that wasnt necessary... Not open sourced (yet), because not proven in production api still in flux need to pluginize (gemize) needs performance tuning not thread safe (uses class variables) it's still Rails 2.02 lack of time