Skip to content
This repository
Browse code

Deprecating composed_of in ActiveRecord

This feature adds a lot of complication to ActiveRecord for dubious
value. Let's talk about what it does currently:

class Customer < ActiveRecord::Base
  composed_of :balance, :class_name => "Money", :mapping => %w(balance
amount)
end

Instead, you can do something like this:

    def balance
      @balance ||= Money.new(value, currency)
    end

    def balance=(balance)
      self[:value] = balance.value
      self[:currency] = balance.currency
      @balance = balance
    end

Since that's fairly easy code to write, and doesn't need anything
extra from the framework, if you use composed_of today, you'll
have to add accessors/mutators like that.

This feature will be removed in Rails 4.
  • Loading branch information...
commit 44b313bc4e3762da64dde7894548f81c595147de 1 parent a8e22ae
Steve Klabnik authored June 15, 2012
6  activerecord/CHANGELOG.md
Source Rendered
... ...
@@ -1,5 +1,11 @@
1 1
 ## Rails 3.2.7 (unreleased) ##
2 2
 
  3
+*   `composed_of` has been deprecated. You'll have to write your own accessor
  4
+    and mutator methods if you'd like to use value objects to represent some
  5
+    portion of your models.
  6
+
  7
+    *Steve Klabnik*
  8
+
3 9
 *   `update_attribute` has been deprecated. Use `update_column` if
4 10
     you want to bypass mass-assignment protection, validations, callbacks,
5 11
     and touching of updated_at. Otherwise please use `update_attributes`.
3  activerecord/lib/active_record/aggregations.rb
@@ -161,6 +161,8 @@ def clear_aggregation_cache #:nodoc:
161 161
     #
162 162
     #   Customer.where(:balance => Money.new(20, "USD")).all
163 163
     #
  164
+    # Note: +composed_of+ has been deprecated, and will be removed (with no
  165
+    # replacement) in Rails 4.
164 166
     module ClassMethods
165 167
       # Adds reader and writer methods for manipulating a value object:
166 168
       # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods.
@@ -203,6 +205,7 @@ module ClassMethods
203 205
       #               :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
204 206
       #
205 207
       def composed_of(part_id, options = {})
  208
+        ActiveSupport::Deprecation.warn("composed_of is deprecated, and will be removed in Rails 4. There is no replacement.")
206 209
         options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
207 210
 
208 211
         name        = part_id.id2name
8  activerecord/test/cases/aggregations_test.rb
@@ -126,11 +126,15 @@ class Name; end
126 126
   class DifferentName; end
127 127
 
128 128
   class Person < ActiveRecord::Base
129  
-    composed_of :composed_of, :mapping => %w(person_first_name first_name)
  129
+    ActiveSupport::Deprecation.silence do
  130
+      composed_of :composed_of, :mapping => %w(person_first_name first_name)
  131
+    end
130 132
   end
131 133
 
132 134
   class DifferentPerson < Person
133  
-    composed_of :composed_of, :class_name => 'DifferentName', :mapping => %w(different_person_first_name first_name)
  135
+    ActiveSupport::Deprecation.silence do
  136
+      composed_of :composed_of, :class_name => 'DifferentName', :mapping => %w(different_person_first_name first_name)
  137
+    end
134 138
   end
135 139
 
136 140
   def test_composed_of_aggregation_redefinition_reflections_should_differ_and_not_inherited
10  activerecord/test/models/customer.rb
... ...
@@ -1,8 +1,10 @@
1 1
 class Customer < ActiveRecord::Base
2  
-  composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true
3  
-  composed_of :balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| balance.to_money }
4  
-  composed_of :gps_location, :allow_nil => true
5  
-  composed_of :fullname, :mapping => %w(name to_s), :constructor => Proc.new { |name| Fullname.parse(name) }, :converter => :parse
  2
+  ActiveSupport::Deprecation.silence do
  3
+    composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true
  4
+    composed_of :balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| balance.to_money }
  5
+    composed_of :gps_location, :allow_nil => true
  6
+    composed_of :fullname, :mapping => %w(name to_s), :constructor => Proc.new { |name| Fullname.parse(name) }, :converter => :parse
  7
+  end
6 8
 end
7 9
 
8 10
 class Address
4  activerecord/test/models/developer.rb
@@ -73,7 +73,9 @@ class AuditLog < ActiveRecord::Base
73 73
 DeveloperSalary = Struct.new(:amount)
74 74
 class DeveloperWithAggregate < ActiveRecord::Base
75 75
   self.table_name = 'developers'
76  
-  composed_of :salary, :class_name => 'DeveloperSalary', :mapping => [%w(salary amount)]
  76
+  ActiveSupport::Deprecation.silence do
  77
+    composed_of :salary, :class_name => 'DeveloperSalary', :mapping => [%w(salary amount)]
  78
+  end
77 79
 end
78 80
 
79 81
 class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base

0 notes on commit 44b313b

Please sign in to comment.
Something went wrong with that request. Please try again.