• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Composed of

Composed of



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

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



Total Views
Views on SlideShare
Embed Views



0 Embeds 0

No embeds


Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Composed of Composed of Presentation Transcript

  • composed_offlat_data.convert_to(rich_ruby_object) most material from Chad Fowler’s “Rails Recipes”, pragprog.com
  • 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
  • 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.”
  • CourseRecord classclass CourseRecord < ActiveRecord::Base composed_of :grade, :mapping => %w(letter_grade letter_grade)end
  • Grade classclass Grade attr_accessor :letter_grade def initialize(letter_grade) @letter_grade = letter_grade endend
  • 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
  • Things to remember• include Comparable and define <=> in order to compare composed_of classes
  • 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
  • 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
  • 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
  • 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
  • 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