DynamicRecord Presentation

1,437 views

Published on

DynamicRecord extends the Ruby on Rails’ ActiveRecord
(AR) object-relational mapping (ORM) module, enabling creation of
dynamic attributes that look and behave like standard AR ones without
the need to add tables or columns to the database.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,437
On SlideShare
0
From Embeds
0
Number of Embeds
17
Actions
Shares
0
Downloads
11
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

DynamicRecord Presentation

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

×