Composed of

0 views
1,468 views

Published on

My SD Ruby talk on using Rails' composed_of macro to add rich behavior to model attributes

Published in: Design, Education, Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
0
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
13
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Composed of

    1. 1. composed_offlat_data.convert_to(rich_ruby_object) most material from Chad Fowler’s “Rails Recipes”, pragprog.com
    2. 2. The Needs• You have a simple model attribute that needs additional behavior but don’t want to create an additional ActiveRecord model• You need to store structured data in the same table as your model but treat it as a first-class, normalized object
    3. 3. composed_ofclass SomeModel < ActiveRecord::Base composed_of :some_attribute, :class_name => SomeSpecialClass, :mapping => [%w(model_attr_name special_class_attr)]end“Add some_attribute, composed of SomeSpecialClass,and map SomeModel’s model_attr_name field tospecial_class_attr.”
    4. 4. CourseRecord classclass CourseRecord < ActiveRecord::Base composed_of :grade, :mapping => %w(letter_grade letter_grade)end
    5. 5. Grade classclass Grade attr_accessor :letter_grade def initialize(letter_grade) @letter_grade = letter_grade endend
    6. 6. class Grade include Comparable attr_accessor :letter_grade course_records def initialize(letter_grade) @letter_grade = letter_gradeid endcourse_id endstudent_idletter_grade class CourseRecord < ActiveRecord::Base composed_of :grade, :mapping => %w(letter_grade letter_grade) end
    7. 7. Things to remember• include Comparable and define <=> in order to compare composed_of classes
    8. 8. class Grade Grade class include Comparable SORT_ORDER = ["F", "D", "D", "B", "A"].inject({}) {|h, letter| h.update "#{letter}-" => h.size h.update letter => h.size h.update "#{letter}+" => h.size } def <=>(other) SORT_ORDER[letter_grade.downcase] <=> SORT_ORDER[other.letter_grade.downcase] endend
    9. 9. Things to remember• composed_of objects are value objects and are immutable!• Create a new object to change the AR model’s composed_of attr
    10. 10. Structured Data person class Person < ActiveRecord::Baseidfirst_name composed_of :address, :mapping =>last_name [ %w(address_street street),address_streetaddress_city %w(address_city city),address_state %w(address_state state),address_countryemail %w(address_country country) ] end
    11. 11. class Address Address class attr_accessor :street, :city, :state, :country def initialize(street, city, state, country) @street = street @city = city @state = state @country = country end def full_address “#{street} #{city}, #{state} #{country}” endend
    12. 12. The Results• Keep your Models DRY and put the responsibilities and behaviors where they belong• Reuse the composed_of models instead of repeating methods in multiple classes• Store structured data flatly but treat it as a first- class Ruby object• Don’t garbage-up your models with lots of “formatting” methods like :full_address

    ×