Skip to content
This repository
Browse code

Removing composed_of from 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.

Closes #1436
Closes #2084
Closes #3807
  • Loading branch information...
commit 14fc8b34521f8354a17e50cd11fa3f809e423592 1 parent 5683946
Steve Klabnik authored June 15, 2012
12  activerecord/README.rdoc
Source Rendered
@@ -46,18 +46,6 @@ A short rundown of some of the major features:
46 46
   {Learn more}[link:classes/ActiveRecord/Associations/ClassMethods.html]
47 47
 
48 48
 
49  
-* Aggregations of value objects.
50  
-
51  
-   class Account < ActiveRecord::Base
52  
-     composed_of :balance, :class_name => "Money",
53  
-                 :mapping => %w(balance amount)
54  
-     composed_of :address,
55  
-                 :mapping => [%w(address_street street), %w(address_city city)]
56  
-   end
57  
-
58  
-  {Learn more}[link:classes/ActiveRecord/Aggregations/ClassMethods.html]
59  
-
60  
-
61 49
 * Validation rules that can differ for new or existing objects.
62 50
 
63 51
     class Account < ActiveRecord::Base
1  activerecord/lib/active_record.rb
@@ -36,7 +36,6 @@ module ActiveRecord
36 36
     autoload :ConnectionNotEstablished, 'active_record/errors'
37 37
     autoload :ConnectionAdapters, 'active_record/connection_adapters/abstract_adapter'
38 38
 
39  
-    autoload :Aggregations
40 39
     autoload :Associations
41 40
     autoload :AttributeMethods
42 41
     autoload :AttributeAssignment
261  activerecord/lib/active_record/aggregations.rb
... ...
@@ -1,261 +0,0 @@
1  
-module ActiveRecord
2  
-  # = Active Record Aggregations
3  
-  module Aggregations # :nodoc:
4  
-    extend ActiveSupport::Concern
5  
-
6  
-    def clear_aggregation_cache #:nodoc:
7  
-      @aggregation_cache.clear if persisted?
8  
-    end
9  
-
10  
-    # Active Record implements aggregation through a macro-like class method called +composed_of+
11  
-    # for representing attributes  as value objects. It expresses relationships like "Account [is]
12  
-    # composed of Money [among other things]" or "Person [is] composed of [an] address". Each call
13  
-    # to the macro adds a description of how the value objects are created from the attributes of
14  
-    # the entity object (when the entity is initialized either as a new object or from finding an
15  
-    # existing object) and how it can be turned back into attributes (when the entity is saved to
16  
-    # the database).
17  
-    #
18  
-    #   class Customer < ActiveRecord::Base
19  
-    #     composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
20  
-    #     composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
21  
-    #   end
22  
-    #
23  
-    # The customer class now has the following methods to manipulate the value objects:
24  
-    # * <tt>Customer#balance, Customer#balance=(money)</tt>
25  
-    # * <tt>Customer#address, Customer#address=(address)</tt>
26  
-    #
27  
-    # These methods will operate with value objects like the ones described below:
28  
-    #
29  
-    #  class Money
30  
-    #    include Comparable
31  
-    #    attr_reader :amount, :currency
32  
-    #    EXCHANGE_RATES = { "USD_TO_DKK" => 6 }
33  
-    #
34  
-    #    def initialize(amount, currency = "USD")
35  
-    #      @amount, @currency = amount, currency
36  
-    #    end
37  
-    #
38  
-    #    def exchange_to(other_currency)
39  
-    #      exchanged_amount = (amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor
40  
-    #      Money.new(exchanged_amount, other_currency)
41  
-    #    end
42  
-    #
43  
-    #    def ==(other_money)
44  
-    #      amount == other_money.amount && currency == other_money.currency
45  
-    #    end
46  
-    #
47  
-    #    def <=>(other_money)
48  
-    #      if currency == other_money.currency
49  
-    #        amount <=> other_money.amount
50  
-    #      else
51  
-    #        amount <=> other_money.exchange_to(currency).amount
52  
-    #      end
53  
-    #    end
54  
-    #  end
55  
-    #
56  
-    #  class Address
57  
-    #    attr_reader :street, :city
58  
-    #    def initialize(street, city)
59  
-    #      @street, @city = street, city
60  
-    #    end
61  
-    #
62  
-    #    def close_to?(other_address)
63  
-    #      city == other_address.city
64  
-    #    end
65  
-    #
66  
-    #    def ==(other_address)
67  
-    #      city == other_address.city && street == other_address.street
68  
-    #    end
69  
-    #  end
70  
-    #
71  
-    # Now it's possible to access attributes from the database through the value objects instead. If
72  
-    # you choose to name the composition the same as the attribute's name, it will be the only way to
73  
-    # access that attribute. That's the case with our +balance+ attribute. You interact with the value
74  
-    # objects just like you would with any other attribute:
75  
-    #
76  
-    #   customer.balance = Money.new(20)     # sets the Money value object and the attribute
77  
-    #   customer.balance                     # => Money value object
78  
-    #   customer.balance.exchange_to("DKK")  # => Money.new(120, "DKK")
79  
-    #   customer.balance > Money.new(10)     # => true
80  
-    #   customer.balance == Money.new(20)    # => true
81  
-    #   customer.balance < Money.new(5)      # => false
82  
-    #
83  
-    # Value objects can also be composed of multiple attributes, such as the case of Address. The order
84  
-    # of the mappings will determine the order of the parameters.
85  
-    #
86  
-    #   customer.address_street = "Hyancintvej"
87  
-    #   customer.address_city   = "Copenhagen"
88  
-    #   customer.address        # => Address.new("Hyancintvej", "Copenhagen")
89  
-    #
90  
-    #   customer.address_street = "Vesterbrogade"
91  
-    #   customer.address        # => Address.new("Hyancintvej", "Copenhagen")
92  
-    #   customer.clear_aggregation_cache
93  
-    #   customer.address        # => Address.new("Vesterbrogade", "Copenhagen")
94  
-    #
95  
-    #   customer.address = Address.new("May Street", "Chicago")
96  
-    #   customer.address_street # => "May Street"
97  
-    #   customer.address_city   # => "Chicago"
98  
-    #
99  
-    # == Writing value objects
100  
-    #
101  
-    # Value objects are immutable and interchangeable objects that represent a given value, such as
102  
-    # a Money object representing $5. Two Money objects both representing $5 should be equal (through
103  
-    # methods such as <tt>==</tt> and <tt><=></tt> from Comparable if ranking makes sense). This is
104  
-    # unlike entity objects where equality is determined by identity. An entity class such as Customer can
105  
-    # easily have two different objects that both have an address on Hyancintvej. Entity identity is
106  
-    # determined by object or relational unique identifiers (such as primary keys). Normal
107  
-    # ActiveRecord::Base classes are entity objects.
108  
-    #
109  
-    # It's also important to treat the value objects as immutable. Don't allow the Money object to have
110  
-    # its amount changed after creation. Create a new Money object with the new value instead. The
111  
-    # Money#exchange_to method is an example of this. It returns a new value object instead of changing
112  
-    # its own values. Active Record won't persist value objects that have been changed through means
113  
-    # other than the writer method.
114  
-    #
115  
-    # The immutable requirement is enforced by Active Record by freezing any object assigned as a value
116  
-    # object. Attempting to change it afterwards will result in a ActiveSupport::FrozenObjectError.
117  
-    #
118  
-    # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not
119  
-    # keeping value objects immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
120  
-    #
121  
-    # == Custom constructors and converters
122  
-    #
123  
-    # By default value objects are initialized by calling the <tt>new</tt> constructor of the value
124  
-    # class passing each of the mapped attributes, in the order specified by the <tt>:mapping</tt>
125  
-    # option, as arguments. If the value class doesn't support this convention then +composed_of+ allows
126  
-    # a custom constructor to be specified.
127  
-    #
128  
-    # When a new value is assigned to the value object, the default assumption is that the new value
129  
-    # is an instance of the value class. Specifying a custom converter allows the new value to be automatically
130  
-    # converted to an instance of value class if necessary.
131  
-    #
132  
-    # For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that
133  
-    # should be aggregated using the NetAddr::CIDR value class (http://netaddr.rubyforge.org). The constructor
134  
-    # for the value class is called +create+ and it expects a CIDR address string as a parameter. New
135  
-    # values can be assigned to the value object using either another NetAddr::CIDR object, a string
136  
-    # or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
137  
-    # these requirements:
138  
-    #
139  
-    #   class NetworkResource < ActiveRecord::Base
140  
-    #     composed_of :cidr,
141  
-    #                 :class_name => 'NetAddr::CIDR',
142  
-    #                 :mapping => [ %w(network_address network), %w(cidr_range bits) ],
143  
-    #                 :allow_nil => true,
144  
-    #                 :constructor => Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
145  
-    #                 :converter => Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
146  
-    #   end
147  
-    #
148  
-    #   # This calls the :constructor
149  
-    #   network_resource = NetworkResource.new(:network_address => '192.168.0.1', :cidr_range => 24)
150  
-    #
151  
-    #   # These assignments will both use the :converter
152  
-    #   network_resource.cidr = [ '192.168.2.1', 8 ]
153  
-    #   network_resource.cidr = '192.168.0.1/24'
154  
-    #
155  
-    #   # This assignment won't use the :converter as the value is already an instance of the value class
156  
-    #   network_resource.cidr = NetAddr::CIDR.create('192.168.2.1/8')
157  
-    #
158  
-    #   # Saving and then reloading will use the :constructor on reload
159  
-    #   network_resource.save
160  
-    #   network_resource.reload
161  
-    #
162  
-    # == Finding records by a value object
163  
-    #
164  
-    # Once a +composed_of+ relationship is specified for a model, records can be loaded from the database
165  
-    # by specifying an instance of the value object in the conditions hash. The following example
166  
-    # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD":
167  
-    #
168  
-    #   Customer.where(:balance => Money.new(20, "USD")).all
169  
-    #
170  
-    module ClassMethods
171  
-      # Adds reader and writer methods for manipulating a value object:
172  
-      # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods.
173  
-      #
174  
-      # Options are:
175  
-      # * <tt>:class_name</tt> - Specifies the class name of the association. Use it only if that name
176  
-      #   can't be inferred from the part id. So <tt>composed_of :address</tt> will by default be linked
177  
-      #   to the Address class, but if the real class name is CompanyAddress, you'll have to specify it
178  
-      #   with this option.
179  
-      # * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value
180  
-      #   object. Each mapping is represented as an array where the first item is the name of the
181  
-      #   entity attribute and the second item is the name of the attribute in the value object. The
182  
-      #   order in which mappings are defined determines the order in which attributes are sent to the
183  
-      #   value class constructor.
184  
-      # * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped
185  
-      #   attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
186  
-      #   mapped attributes.
187  
-      #   This defaults to +false+.
188  
-      # * <tt>:constructor</tt> - A symbol specifying the name of the constructor method or a Proc that
189  
-      #   is called to initialize the value object. The constructor is passed all of the mapped attributes,
190  
-      #   in the order that they are defined in the <tt>:mapping option</tt>, as arguments and uses them
191  
-      #   to instantiate a <tt>:class_name</tt> object.
192  
-      #   The default is <tt>:new</tt>.
193  
-      # * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt>
194  
-      #   or a Proc that is called when a new value is assigned to the value object. The converter is
195  
-      #   passed the single value that is used in the assignment and is only called if the new value is
196  
-      #   not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter
197  
-      #   can return nil to skip the assignment.
198  
-      #
199  
-      # Option examples:
200  
-      #   composed_of :temperature, :mapping => %w(reading celsius)
201  
-      #   composed_of :balance, :class_name => "Money", :mapping => %w(balance amount),
202  
-      #                         :converter => Proc.new { |balance| balance.to_money }
203  
-      #   composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
204  
-      #   composed_of :gps_location
205  
-      #   composed_of :gps_location, :allow_nil => true
206  
-      #   composed_of :ip_address,
207  
-      #               :class_name => 'IPAddr',
208  
-      #               :mapping => %w(ip to_i),
209  
-      #               :constructor => Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
210  
-      #               :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
211  
-      #
212  
-      def composed_of(part_id, options = {})
213  
-        options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
214  
-
215  
-        name        = part_id.id2name
216  
-        class_name  = options[:class_name]  || name.camelize
217  
-        mapping     = options[:mapping]     || [ name, name ]
218  
-        mapping     = [ mapping ] unless mapping.first.is_a?(Array)
219  
-        allow_nil   = options[:allow_nil]   || false
220  
-        constructor = options[:constructor] || :new
221  
-        converter   = options[:converter]
222  
-
223  
-        reader_method(name, class_name, mapping, allow_nil, constructor)
224  
-        writer_method(name, class_name, mapping, allow_nil, converter)
225  
-
226  
-        create_reflection(:composed_of, part_id, options, self)
227  
-      end
228  
-
229  
-      private
230  
-        def reader_method(name, class_name, mapping, allow_nil, constructor)
231  
-          define_method(name) do
232  
-            if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|pair| !read_attribute(pair.first).nil? })
233  
-              attrs = mapping.collect {|pair| read_attribute(pair.first)}
234  
-              object = constructor.respond_to?(:call) ?
235  
-                constructor.call(*attrs) :
236  
-                class_name.constantize.send(constructor, *attrs)
237  
-              @aggregation_cache[name] = object
238  
-            end
239  
-            @aggregation_cache[name]
240  
-          end
241  
-        end
242  
-
243  
-        def writer_method(name, class_name, mapping, allow_nil, converter)
244  
-          define_method("#{name}=") do |part|
245  
-            klass = class_name.constantize
246  
-            unless part.is_a?(klass) || converter.nil? || part.nil?
247  
-              part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
248  
-            end
249  
-
250  
-            if part.nil? && allow_nil
251  
-              mapping.each { |pair| self[pair.first] = nil }
252  
-              @aggregation_cache[name] = nil
253  
-            else
254  
-              mapping.each { |pair| self[pair.first] = part.send(pair.last) }
255  
-              @aggregation_cache[name] = part.freeze
256  
-            end
257  
-          end
258  
-        end
259  
-    end
260  
-  end
261  
-end
4  activerecord/lib/active_record/attribute_assignment.rb
@@ -132,7 +132,7 @@ def mass_assignment_role
132 132
     private
133 133
 
134 134
     # Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
135  
-    # by calling new on the column type or aggregation type (through composed_of) object with these parameters.
  135
+    # by calling new on the column type or aggregation type object with these parameters.
136 136
     # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
137 137
     # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
138 138
     # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum,
@@ -167,7 +167,7 @@ def execute_callstack_for_multiparameter_attributes(callstack)
167 167
     end
168 168
 
169 169
     def read_value_from_parameter(name, values_hash_from_param)
170  
-      klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass
  170
+      klass = column_for_attribute(name).klass
171 171
       if values_hash_from_param.values.all?{|v|v.nil?}
172 172
         nil
173 173
       elsif klass == Time
2  activerecord/lib/active_record/core.rb
@@ -266,7 +266,6 @@ def initialize_dup(other) # :nodoc:
266 266
         @changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
267 267
       end
268 268
 
269  
-      @aggregation_cache = {}
270 269
       @association_cache = {}
271 270
       @attributes_cache  = {}
272 271
 
@@ -391,7 +390,6 @@ def init_internals
391 390
 
392 391
       @attributes[pk] = nil unless @attributes.key?(pk)
393 392
 
394  
-      @aggregation_cache       = {}
395 393
       @association_cache       = {}
396 394
       @attributes_cache        = {}
397 395
       @previously_changed      = {}
2  activerecord/lib/active_record/dynamic_matchers.rb
@@ -56,7 +56,7 @@ def initialize(model, name)
56 56
       end
57 57
 
58 58
       def valid?
59  
-        attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
  59
+        attribute_names.all? { |name| model.columns_hash[name] }
60 60
       end
61 61
 
62 62
       def define
1  activerecord/lib/active_record/model.rb
@@ -89,7 +89,6 @@ def self.append_features(base)
89 89
     include ActiveModel::SecurePassword
90 90
     include AutosaveAssociation
91 91
     include NestedAttributes
92  
-    include Aggregations
93 92
     include Transactions
94 93
     include Reflection
95 94
     include Serialization
1  activerecord/lib/active_record/persistence.rb
@@ -267,7 +267,6 @@ def toggle!(attribute)
267 267
     # may do e.g. record.reload(:lock => true) to reload the same record with
268 268
     # an exclusive row lock.
269 269
     def reload(options = nil)
270  
-      clear_aggregation_cache
271 270
       clear_association_cache
272 271
 
273 272
       fresh_object =
45  activerecord/lib/active_record/reflection.rb
@@ -17,36 +17,17 @@ module Reflection # :nodoc:
17 17
     # and creates input fields for all of the attributes depending on their type
18 18
     # and displays the associations to other objects.
19 19
     #
20  
-    # MacroReflection class has info for AggregateReflection and AssociationReflection
21  
-    # classes.
  20
+    # MacroReflection class has info for the AssociationReflection
  21
+    # class.
22 22
     module ClassMethods
23 23
       def create_reflection(macro, name, options, active_record)
24  
-        case macro
25  
-        when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many
26  
-          klass = options[:through] ? ThroughReflection : AssociationReflection
27  
-          reflection = klass.new(macro, name, options, active_record)
28  
-        when :composed_of
29  
-          reflection = AggregateReflection.new(macro, name, options, active_record)
30  
-        end
  24
+        klass = options[:through] ? ThroughReflection : AssociationReflection
  25
+        reflection = klass.new(macro, name, options, active_record)
31 26
 
32 27
         self.reflections = self.reflections.merge(name => reflection)
33 28
         reflection
34 29
       end
35 30
 
36  
-      # Returns an array of AggregateReflection objects for all the aggregations in the class.
37  
-      def reflect_on_all_aggregations
38  
-        reflections.values.grep(AggregateReflection)
39  
-      end
40  
-
41  
-      # Returns the AggregateReflection object for the named +aggregation+ (use the symbol).
42  
-      #
43  
-      #   Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
44  
-      #
45  
-      def reflect_on_aggregation(aggregation)
46  
-        reflection = reflections[aggregation]
47  
-        reflection if reflection.is_a?(AggregateReflection)
48  
-      end
49  
-
50 31
       # Returns an array of AssociationReflection objects for all the
51 32
       # associations in the class. If you only want to reflect on a certain
52 33
       # association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>,
@@ -78,24 +59,20 @@ def reflect_on_all_autosave_associations
78 59
       end
79 60
     end
80 61
 
81  
-    # Abstract base class for AggregateReflection and AssociationReflection. Objects of
82  
-    # AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
  62
+    # Abstract base class for AssociationReflection. Objects of AssociationReflection are returned by the Reflection::ClassMethods.
83 63
     class MacroReflection
84 64
       # Returns the name of the macro.
85 65
       #
86  
-      # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>:balance</tt>
87 66
       # <tt>has_many :clients</tt> returns <tt>:clients</tt>
88 67
       attr_reader :name
89 68
 
90 69
       # Returns the macro type.
91 70
       #
92  
-      # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>:composed_of</tt>
93 71
       # <tt>has_many :clients</tt> returns <tt>:has_many</tt>
94 72
       attr_reader :macro
95 73
 
96 74
       # Returns the hash of options used for the macro.
97 75
       #
98  
-      # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>{ :class_name => "Money" }</tt>
99 76
       # <tt>has_many :clients</tt> returns +{}+
100 77
       attr_reader :options
101 78
 
@@ -114,7 +91,6 @@ def initialize(macro, name, options, active_record)
114 91
 
115 92
       # Returns the class for the macro.
116 93
       #
117  
-      # <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money class
118 94
       # <tt>has_many :clients</tt> returns the Client class
119 95
       def klass
120 96
         @klass ||= class_name.constantize
@@ -122,7 +98,6 @@ def klass
122 98
 
123 99
       # Returns the class name for the macro.
124 100
       #
125  
-      # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>'Money'</tt>
126 101
       # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
127 102
       def class_name
128 103
         @class_name ||= (options[:class_name] || derive_class_name).to_s
@@ -148,16 +123,6 @@ def derive_class_name
148 123
         end
149 124
     end
150 125
 
151  
-
152  
-    # Holds all the meta-data about an aggregation as it was specified in the
153  
-    # Active Record class.
154  
-    class AggregateReflection < MacroReflection #:nodoc:
155  
-      def mapping
156  
-        mapping = options[:mapping] || [name, name]
157  
-        mapping.first.is_a?(Array) ? mapping : [mapping]
158  
-      end
159  
-    end
160  
-
161 126
     # Holds all the meta-data about an association as it was specified in the
162 127
     # Active Record class.
163 128
     class AssociationReflection < MacroReflection #:nodoc:
3  activerecord/lib/active_record/relation/query_methods.rb
@@ -562,8 +562,7 @@ def build_where(opts, other = [])
562 562
       when String, Array
563 563
         [@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
564 564
       when Hash
565  
-        attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
566  
-        PredicateBuilder.build_from_hash(table.engine, attributes, table)
  565
+        PredicateBuilder.build_from_hash(table.engine, opts, table)
567 566
       else
568 567
         [opts]
569 568
       end
32  activerecord/lib/active_record/sanitization.rb
@@ -43,36 +43,6 @@ def sanitize_sql_for_assignment(assignments)
43 43
         end
44 44
       end
45 45
 
46  
-      # Accepts a hash of SQL conditions and replaces those attributes
47  
-      # that correspond to a +composed_of+ relationship with their expanded
48  
-      # aggregate attribute values.
49  
-      # Given:
50  
-      #     class Person < ActiveRecord::Base
51  
-      #       composed_of :address, :class_name => "Address",
52  
-      #         :mapping => [%w(address_street street), %w(address_city city)]
53  
-      #     end
54  
-      # Then:
55  
-      #     { :address => Address.new("813 abc st.", "chicago") }
56  
-      #       # => { :address_street => "813 abc st.", :address_city => "chicago" }
57  
-      def expand_hash_conditions_for_aggregates(attrs)
58  
-        expanded_attrs = {}
59  
-        attrs.each do |attr, value|
60  
-          if aggregation = reflect_on_aggregation(attr.to_sym)
61  
-            mapping = aggregation.mapping
62  
-            mapping.each do |field_attr, aggregate_attr|
63  
-              if mapping.size == 1 && !value.respond_to?(aggregate_attr)
64  
-                expanded_attrs[field_attr] = value
65  
-              else
66  
-                expanded_attrs[field_attr] = value.send(aggregate_attr)
67  
-              end
68  
-            end
69  
-          else
70  
-            expanded_attrs[attr] = value
71  
-          end
72  
-        end
73  
-        expanded_attrs
74  
-      end
75  
-
76 46
       # Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.
77 47
       #   { :name => "foo'bar", :group_id => 4 }
78 48
       #     # => "name='foo''bar' and group_id= 4"
@@ -88,8 +58,6 @@ def expand_hash_conditions_for_aggregates(attrs)
88 58
       #   { :address => Address.new("123 abc st.", "chicago") }
89 59
       #     # => "address_street='123 abc st.' and address_city='chicago'"
90 60
       def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
91  
-        attrs = expand_hash_conditions_for_aggregates(attrs)
92  
-
93 61
         table = Arel::Table.new(table_name).alias(default_table_name)
94 62
         PredicateBuilder.build_from_hash(arel_engine, attrs, table).map { |b|
95 63
           connection.visitor.accept b
158  activerecord/test/cases/aggregations_test.rb
... ...
@@ -1,158 +0,0 @@
1  
-require "cases/helper"
2  
-require 'models/customer'
3  
-require 'active_support/core_ext/exception'
4  
-
5  
-class AggregationsTest < ActiveRecord::TestCase
6  
-  fixtures :customers
7  
-
8  
-  def test_find_single_value_object
9  
-    assert_equal 50, customers(:david).balance.amount
10  
-    assert_kind_of Money, customers(:david).balance
11  
-    assert_equal 300, customers(:david).balance.exchange_to("DKK").amount
12  
-  end
13  
-
14  
-  def test_find_multiple_value_object
15  
-    assert_equal customers(:david).address_street, customers(:david).address.street
16  
-    assert(
17  
-      customers(:david).address.close_to?(Address.new("Different Street", customers(:david).address_city, customers(:david).address_country))
18  
-    )
19  
-  end
20  
-
21  
-  def test_change_single_value_object
22  
-    customers(:david).balance = Money.new(100)
23  
-    customers(:david).save
24  
-    assert_equal 100, customers(:david).reload.balance.amount
25  
-  end
26  
-
27  
-  def test_immutable_value_objects
28  
-    customers(:david).balance = Money.new(100)
29  
-    assert_raise(ActiveSupport::FrozenObjectError) { customers(:david).balance.instance_eval { @amount = 20 } }
30  
-  end
31  
-
32  
-  def test_inferred_mapping
33  
-    assert_equal "35.544623640962634", customers(:david).gps_location.latitude
34  
-    assert_equal "-105.9309951055148", customers(:david).gps_location.longitude
35  
-
36  
-    customers(:david).gps_location = GpsLocation.new("39x-110")
37  
-
38  
-    assert_equal "39", customers(:david).gps_location.latitude
39  
-    assert_equal "-110", customers(:david).gps_location.longitude
40  
-
41  
-    customers(:david).save
42  
-
43  
-    customers(:david).reload
44  
-
45  
-    assert_equal "39", customers(:david).gps_location.latitude
46  
-    assert_equal "-110", customers(:david).gps_location.longitude
47  
-  end
48  
-
49  
-  def test_reloaded_instance_refreshes_aggregations
50  
-    assert_equal "35.544623640962634", customers(:david).gps_location.latitude
51  
-    assert_equal "-105.9309951055148", customers(:david).gps_location.longitude
52  
-
53  
-    Customer.update_all("gps_location = '24x113'")
54  
-    customers(:david).reload
55  
-    assert_equal '24x113', customers(:david)['gps_location']
56  
-
57  
-    assert_equal GpsLocation.new('24x113'), customers(:david).gps_location
58  
-  end
59  
-
60  
-  def test_gps_equality
61  
-    assert_equal GpsLocation.new('39x110'), GpsLocation.new('39x110')
62  
-  end
63  
-
64  
-  def test_gps_inequality
65  
-    assert_not_equal GpsLocation.new('39x110'), GpsLocation.new('39x111')
66  
-  end
67  
-
68  
-  def test_allow_nil_gps_is_nil
69  
-    assert_nil customers(:zaphod).gps_location
70  
-  end
71  
-
72  
-  def test_allow_nil_gps_set_to_nil
73  
-    customers(:david).gps_location = nil
74  
-    customers(:david).save
75  
-    customers(:david).reload
76  
-    assert_nil customers(:david).gps_location
77  
-  end
78  
-
79  
-  def test_allow_nil_set_address_attributes_to_nil
80  
-    customers(:zaphod).address = nil
81  
-    assert_nil customers(:zaphod).attributes[:address_street]
82  
-    assert_nil customers(:zaphod).attributes[:address_city]
83  
-    assert_nil customers(:zaphod).attributes[:address_country]
84  
-  end
85  
-
86  
-  def test_allow_nil_address_set_to_nil
87  
-    customers(:zaphod).address = nil
88  
-    customers(:zaphod).save
89  
-    customers(:zaphod).reload
90  
-    assert_nil customers(:zaphod).address
91  
-  end
92  
-
93  
-  def test_nil_raises_error_when_allow_nil_is_false
94  
-    assert_raise(NoMethodError) { customers(:david).balance = nil }
95  
-  end
96  
-
97  
-  def test_allow_nil_address_loaded_when_only_some_attributes_are_nil
98  
-    customers(:zaphod).address_street = nil
99  
-    customers(:zaphod).save
100  
-    customers(:zaphod).reload
101  
-    assert_kind_of Address, customers(:zaphod).address
102  
-    assert_nil customers(:zaphod).address.street
103  
-  end
104  
-
105  
-  def test_nil_assignment_results_in_nil
106  
-    customers(:david).gps_location = GpsLocation.new('39x111')
107  
-    assert_not_nil customers(:david).gps_location
108  
-    customers(:david).gps_location = nil
109  
-    assert_nil customers(:david).gps_location
110  
-  end
111  
-
112  
-  def test_nil_return_from_converter_is_respected_when_allow_nil_is_true
113  
-    customers(:david).non_blank_gps_location = ""
114  
-    customers(:david).save
115  
-    customers(:david).reload
116  
-    assert_nil customers(:david).non_blank_gps_location
117  
-  end
118  
-
119  
-  def test_nil_return_from_converter_results_in_failure_when_allow_nil_is_false
120  
-    assert_raises(NoMethodError) do
121  
-      customers(:barney).gps_location = ""
122  
-    end
123  
-  end
124  
-
125  
-  def test_do_not_run_the_converter_when_nil_was_set
126  
-    customers(:david).non_blank_gps_location = nil
127  
-    assert_nil Customer.gps_conversion_was_run
128  
-  end
129  
-
130  
-  def test_custom_constructor
131  
-    assert_equal 'Barney GUMBLE', customers(:barney).fullname.to_s
132  
-    assert_kind_of Fullname, customers(:barney).fullname
133  
-  end
134  
-
135  
-  def test_custom_converter
136  
-    customers(:barney).fullname = 'Barnoit Gumbleau'
137  
-    assert_equal 'Barnoit GUMBLEAU', customers(:barney).fullname.to_s
138  
-    assert_kind_of Fullname, customers(:barney).fullname
139  
-  end
140  
-end
141  
-
142  
-class OverridingAggregationsTest < ActiveRecord::TestCase
143  
-  class Name; end
144  
-  class DifferentName; end
145  
-
146  
-  class Person < ActiveRecord::Base
147  
-    composed_of :composed_of, :mapping => %w(person_first_name first_name)
148  
-  end
149  
-
150  
-  class DifferentPerson < Person
151  
-    composed_of :composed_of, :class_name => 'DifferentName', :mapping => %w(different_person_first_name first_name)
152  
-  end
153  
-
154  
-  def test_composed_of_aggregation_redefinition_reflections_should_differ_and_not_inherited
155  
-    assert_not_equal Person.reflect_on_aggregation(:composed_of),
156  
-                     DifferentPerson.reflect_on_aggregation(:composed_of)
157  
-  end
158  
-end
44  activerecord/test/cases/base_test.rb
@@ -888,22 +888,6 @@ def test_multiparameter_attributes_on_time_with_empty_seconds
888 888
     assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
889 889
   end
890 890
 
891  
-  def test_multiparameter_assignment_of_aggregation
892  
-    customer = Customer.new
893  
-    address = Address.new("The Street", "The City", "The Country")
894  
-    attributes = { "address(1)" => address.street, "address(2)" => address.city, "address(3)" => address.country }
895  
-    customer.attributes = attributes
896  
-    assert_equal address, customer.address
897  
-  end
898  
-
899  
-  def test_multiparameter_assignment_of_aggregation_out_of_order
900  
-    customer = Customer.new
901  
-    address = Address.new("The Street", "The City", "The Country")
902  
-    attributes = { "address(3)" => address.country, "address(2)" => address.city, "address(1)" => address.street }
903  
-    customer.attributes = attributes
904  
-    assert_equal address, customer.address
905  
-  end
906  
-
907 891
   def test_multiparameter_assignment_of_aggregation_with_missing_values
908 892
     ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
909 893
       customer = Customer.new
@@ -914,14 +898,6 @@ def test_multiparameter_assignment_of_aggregation_with_missing_values
914 898
     assert_equal("address", ex.errors[0].attribute)
915 899
   end
916 900
 
917  
-  def test_multiparameter_assignment_of_aggregation_with_blank_values
918  
-    customer = Customer.new
919  
-    address = Address.new("The Street", "The City", "The Country")
920  
-    attributes = { "address(1)" => "", "address(2)" => address.city, "address(3)" => address.country }
921  
-    customer.attributes = attributes
922  
-    assert_equal Address.new(nil, "The City", "The Country"), customer.address
923  
-  end
924  
-
925 901
   def test_multiparameter_assignment_of_aggregation_with_large_index
926 902
     ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
927 903
       customer = Customer.new
@@ -1021,26 +997,6 @@ def test_dup
1021 997
     assert_equal("c", duped_topic.title)
1022 998
   end
1023 999
 
1024  
-  def test_dup_with_aggregate_of_same_name_as_attribute
1025  
-    dev = DeveloperWithAggregate.find(1)
1026  
-    assert_kind_of DeveloperSalary, dev.salary
1027  
-
1028  
-    dup = nil
1029  
-    assert_nothing_raised { dup = dev.dup }
1030  
-    assert_kind_of DeveloperSalary, dup.salary
1031  
-    assert_equal dev.salary.amount, dup.salary.amount
1032  
-    assert !dup.persisted?
1033  
-
1034  
-    # test if the attributes have been dupd
1035  
-    original_amount = dup.salary.amount
1036  
-    dev.salary.amount = 1
1037  
-    assert_equal original_amount, dup.salary.amount
1038  
-
1039  
-    assert dup.save
1040  
-    assert dup.persisted?
1041  
-    assert_not_equal dup.id, dev.id
1042  
-  end
1043  
-
1044 1000
   def test_dup_does_not_copy_associations
1045 1001
     author = authors(:david)
1046 1002
     assert_not_equal [], author.posts
76  activerecord/test/cases/deprecated_dynamic_methods_test.rb
@@ -45,32 +45,6 @@ def test_find_all_by_one_attribute_which_is_a_symbol
45 45
     assert_equal [], Topic.find_all_by_title("The First Topic!!")
46 46
   end
47 47
 
48  
-  def test_find_all_by_one_attribute_that_is_an_aggregate
49  
-    balance = customers(:david).balance
50  
-    assert_kind_of Money, balance
51  
-    found_customers = Customer.find_all_by_balance(balance)
52  
-    assert_equal 1, found_customers.size
53  
-    assert_equal customers(:david), found_customers.first
54  
-  end
55  
-
56  
-  def test_find_all_by_two_attributes_that_are_both_aggregates
57  
-    balance = customers(:david).balance
58  
-    address = customers(:david).address
59  
-    assert_kind_of Money, balance
60  
-    assert_kind_of Address, address
61  
-    found_customers = Customer.find_all_by_balance_and_address(balance, address)
62  
-    assert_equal 1, found_customers.size
63  
-    assert_equal customers(:david), found_customers.first
64  
-  end
65  
-
66  
-  def test_find_all_by_two_attributes_with_one_being_an_aggregate
67  
-    balance = customers(:david).balance
68  
-    assert_kind_of Money, balance
69  
-    found_customers = Customer.find_all_by_balance_and_name(balance, customers(:david).name)
70  
-    assert_equal 1, found_customers.size
71  
-    assert_equal customers(:david), found_customers.first
72  
-  end
73  
-
74 48
   def test_find_all_by_one_attribute_with_options
75 49
     topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC")
76 50
     assert_equal topics(:first), topics.last
@@ -137,14 +111,6 @@ def test_find_or_create_from_two_attributes_bang
137 111
     assert_equal 17, sig38.firm_id
138 112
   end
139 113
 
140  
-  def test_find_or_create_from_two_attributes_with_one_being_an_aggregate
141  
-    number_of_customers = Customer.count
142  
-    created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth")
143  
-    assert_equal number_of_customers + 1, Customer.count
144  
-    assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth")
145  
-    assert created_customer.persisted?
146  
-  end
147  
-
148 114
   def test_find_or_create_from_one_attribute_and_hash
149 115
     number_of_companies = Company.count
150 116
     sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
@@ -167,38 +133,12 @@ def test_find_or_create_from_two_attributes_and_hash
167 133
     assert_equal 23, sig38.client_of
168 134
   end
169 135
 
170  
-  def test_find_or_create_from_one_aggregate_attribute
171  
-    number_of_customers = Customer.count
172  
-    created_customer = Customer.find_or_create_by_balance(Money.new(123))
173  
-    assert_equal number_of_customers + 1, Customer.count
174  
-    assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123))
175  
-    assert created_customer.persisted?
176  
-  end
177  
-
178  
-  def test_find_or_create_from_one_aggregate_attribute_and_hash
179  
-    number_of_customers = Customer.count
180  
-    balance = Money.new(123)
181  
-    name = "Elizabeth"
182  
-    created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name})
183  
-    assert_equal number_of_customers + 1, Customer.count
184  
-    assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name})
185  
-    assert created_customer.persisted?
186  
-    assert_equal balance, created_customer.balance
187  
-    assert_equal name, created_customer.name
188  
-  end
189  
-
190 136
   def test_find_or_initialize_from_one_attribute
191 137
     sig38 = Company.find_or_initialize_by_name("38signals")
192 138
     assert_equal "38signals", sig38.name
193 139
     assert !sig38.persisted?
194 140
   end
195 141
 
196  
-  def test_find_or_initialize_from_one_aggregate_attribute
197  
-    new_customer = Customer.find_or_initialize_by_balance(Money.new(123))
198  
-    assert_equal 123, new_customer.balance.amount
199  
-    assert !new_customer.persisted?
200  
-  end
201  
-
202 142
   def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected
203 143
     c = Company.find_or_initialize_by_name({:name => "Fortune 1000", :rating => 1000})
204 144
     assert_equal "Fortune 1000", c.name
@@ -285,13 +225,6 @@ def test_find_or_initialize_from_two_attributes_but_passing_only_one
285 225
     assert_raise(ArgumentError) { Topic.find_or_initialize_by_title_and_author_name("Another topic") }
286 226
   end
287 227
 
288  
-  def test_find_or_initialize_from_one_aggregate_attribute_and_one_not
289  
-    new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth")
290  
-    assert_equal 123, new_customer.balance.amount
291  
-    assert_equal "Elizabeth", new_customer.name
292  
-    assert !new_customer.persisted?
293  
-  end
294  
-
295 228
   def test_find_or_initialize_from_one_attribute_and_hash
296 229
     sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
297 230
     assert_equal "38signals", sig38.name
@@ -300,15 +233,6 @@ def test_find_or_initialize_from_one_attribute_and_hash
300 233
     assert !sig38.persisted?
301 234
   end
302 235
 
303  
-  def test_find_or_initialize_from_one_aggregate_attribute_and_hash
304  
-    balance = Money.new(123)
305  
-    name = "Elizabeth"
306  
-    new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name})
307  
-    assert_equal balance, new_customer.balance
308  
-    assert_equal name, new_customer.name
309  
-    assert !new_customer.persisted?
310  
-  end
311  
-
312 236
   def test_find_last_by_one_attribute
313 237
     assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title)
314 238
     assert_nil Topic.find_last_by_title("A title with no matches")
99  activerecord/test/cases/finder_test.rb
@@ -79,21 +79,6 @@ def test_exists_with_empty_table_and_no_args_given
79 79
     assert !Topic.exists?
80 80
   end
81 81
 
82  
-  def test_exists_with_aggregate_having_three_mappings
83  
-    existing_address = customers(:david).address
84  
-    assert Customer.exists?(:address => existing_address)
85  
-  end
86  
-
87  
-  def test_exists_with_aggregate_having_three_mappings_with_one_difference
88  
-    existing_address = customers(:david).address
89  
-    assert !Customer.exists?(:address =>
90  
-      Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
91  
-    assert !Customer.exists?(:address =>
92  
-      Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
93  
-    assert !Customer.exists?(:address =>
94  
-      Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
95  
-  end
96  
-
97 82
   def test_exists_does_not_instantiate_records
98 83
     Developer.expects(:instantiate).never
99 84
     Developer.exists?
@@ -312,14 +297,6 @@ def test_find_with_hash_conditions_on_joined_table_and_with_range
312 297
     assert_equal companies(:rails_core), firms.first
313 298
   end
314 299
 
315  
-  def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
316  
-    david = customers(:david)
317  
-    assert Customer.scoped(:where => { 'customers.name' => david.name, :address => david.address }).find(david.id)
318  
-    assert_raise(ActiveRecord::RecordNotFound) {
319  
-      Customer.scoped(:where => { 'customers.name' => david.name + "1", :address => david.address }).find(david.id)
320  
-    }
321  
-  end
322  
-
323 300
   def test_find_on_association_proxy_conditions
324 301
     assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.where(post_id: authors(:david).posts).map(&:id).sort
325 302
   end
@@ -394,48 +371,6 @@ def test_hash_condition_find_with_nil
394 371
     assert_nil topic.last_read
395 372
   end
396 373
 
397  
-  def test_hash_condition_find_with_aggregate_having_one_mapping
398  
-    balance = customers(:david).balance
399  
-    assert_kind_of Money, balance
400  
-    found_customer = Customer.scoped(:where => {:balance => balance}).first
401  
-    assert_equal customers(:david), found_customer
402  
-  end
403  
-
404  
-  def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
405  
-    gps_location = customers(:david).gps_location
406  
-    assert_kind_of GpsLocation, gps_location
407  
-    found_customer = Customer.scoped(:where => {:gps_location => gps_location}).first
408  
-    assert_equal customers(:david), found_customer
409  
-  end
410  
-
411  
-  def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
412  
-    balance = customers(:david).balance
413  
-    assert_kind_of Money, balance
414  
-    found_customer = Customer.scoped(:where => {:balance => balance.amount}).first
415  
-    assert_equal customers(:david), found_customer
416  
-  end
417  
-
418  
-  def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
419  
-    gps_location = customers(:david).gps_location
420  
-    assert_kind_of GpsLocation, gps_location
421  
-    found_customer = Customer.scoped(:where => {:gps_location => gps_location.gps_location}).first
422  
-    assert_equal customers(:david), found_customer
423  
-  end
424  
-
425  
-  def test_hash_condition_find_with_aggregate_having_three_mappings
426  
-    address = customers(:david).address
427  
-    assert_kind_of Address, address
428  
-    found_customer = Customer.scoped(:where => {:address => address}).first
429  
-    assert_equal customers(:david), found_customer
430  
-  end
431  
-
432  
-  def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
433  
-    address = customers(:david).address
434  
-    assert_kind_of Address, address
435  
-    found_customer = Customer.scoped(:where => {:address => address, :name => customers(:david).name}).first
436  
-    assert_equal customers(:david), found_customer
437  
-  end
438  
-
439 374
   def test_condition_utc_time_interpolation_with_default_timezone_local
440 375
     with_env_tz 'America/New_York' do
441 376
       with_active_record_default_timezone :local do
@@ -604,40 +539,6 @@ def test_find_by_one_attribute_with_conditions
604 539
     assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50)
605 540
   end
606 541
 
607  
-  def test_find_by_one_attribute_that_is_an_aggregate
608  
-    address = customers(:david).address
609  
-    assert_kind_of Address, address
610  
-    found_customer = Customer.find_by_address(address)
611  
-    assert_equal customers(:david), found_customer
612  
-  end
613  
-
614  
-  def test_find_by_one_attribute_that_is_an_aggregate_with_one_attribute_difference
615  
-    address = customers(:david).address
616  
-    assert_kind_of Address, address
617  
-    missing_address = Address.new(address.street, address.city, address.country + "1")
618  
-    assert_nil Customer.find_by_address(missing_address)
619  
-    missing_address = Address.new(address.street, address.city + "1", address.country)
620  
-    assert_nil Customer.find_by_address(missing_address)
621  
-    missing_address = Address.new(address.street + "1", address.city, address.country)
622  
-    assert_nil Customer.find_by_address(missing_address)
623  
-  end
624  
-
625  
-  def test_find_by_two_attributes_that_are_both_aggregates
626  
-    balance = customers(:david).balance
627  
-    address = customers(:david).address
628  
-    assert_kind_of Money, balance
629  
-    assert_kind_of Address, address
630  
-    found_customer = Customer.find_by_balance_and_address(balance, address)
631  
-    assert_equal customers(:david), found_customer
632  
-  end
633  
-
634  
-  def test_find_by_two_attributes_with_one_being_an_aggregate
635  
-    balance = customers(:david).balance
636  
-    assert_kind_of Money, balance
637  
-    found_customer = Customer.find_by_balance_and_name(balance, customers(:david).name)
638  
-    assert_equal customers(:david), found_customer
639  
-  end
640  
-
641 542
   def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
642 543
     # ensure this test can run independently of order
643 544
     class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.include?(:find_by_credit_limit)
24  activerecord/test/cases/reflection_test.rb
@@ -83,30 +83,6 @@ def test_reflection_klass_for_nested_class_name
83 83
     end
84 84
   end
85 85
 
86  
-  def test_aggregation_reflection
87  
-    reflection_for_address = AggregateReflection.new(
88  
-      :composed_of, :address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer
89  
-    )
90  
-
91  
-    reflection_for_balance = AggregateReflection.new(
92  
-      :composed_of, :balance, { :class_name => "Money", :mapping => %w(balance amount) }, Customer
93  
-    )
94  
-
95  
-    reflection_for_gps_location = AggregateReflection.new(
96  
-      :composed_of, :gps_location, { }, Customer
97  
-    )
98  
-
99  
-    assert Customer.reflect_on_all_aggregations.include?(reflection_for_gps_location)
100  
-    assert Customer.reflect_on_all_aggregations.include?(reflection_for_balance)
101  
-    assert Customer.reflect_on_all_aggregations.include?(reflection_for_address)
102  
-
103  
-    assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address)
104  
-
105  
-    assert_equal Address, Customer.reflect_on_aggregation(:address).klass
106  
-
107  
-    assert_equal Money, Customer.reflect_on_aggregation(:balance).klass
108  
-  end
109  
-
110 86
   def test_reflect_on_all_autosave_associations
111 87
     expected = Pirate.reflect_on_all_associations.select { |r| r.options[:autosave] }
112 88
     received = Pirate.reflect_on_all_autosave_associations
7  activerecord/test/models/customer.rb
... ...
@@ -1,12 +1,5 @@
1 1
 class Customer < ActiveRecord::Base
2 2
   cattr_accessor :gps_conversion_was_run
3  
-
4  
-  composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true
5  
-  composed_of :balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| balance.to_money }
6  
-  composed_of :gps_location, :allow_nil => true
7  
-  composed_of :non_blank_gps_location, :class_name => "GpsLocation", :allow_nil => true, :mapping => %w(gps_location gps_location),
8  
-              :converter => lambda { |gps| self.gps_conversion_was_run = true; gps.blank? ? nil : GpsLocation.new(gps)}
9  
-  composed_of :fullname, :mapping => %w(name to_s), :constructor => Proc.new { |name| Fullname.parse(name) }, :converter => :parse
10 3
 end
11 4
 
12 5
 class Address
5  activerecord/test/models/developer.rb
@@ -65,11 +65,6 @@ class AuditLog < ActiveRecord::Base
65 65
 end
66 66
 
67 67
 DeveloperSalary = Struct.new(:amount)
68  
-class DeveloperWithAggregate < ActiveRecord::Base
69  
-  self.table_name = 'developers'
70  
-  composed_of :salary, :class_name => 'DeveloperSalary', :mapping => [%w(salary amount)]
71  
-end
72  
-
73 68
 class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base
74 69
   self.table_name = 'developers'
75 70
   has_and_belongs_to_many :projects, :join_table => 'developers_projects', :foreign_key => 'developer_id'

1 note on commit 14fc8b3

Wojtek Kruszewski

with 9 additions and 768 deletions. -- thanks man. Keeping a framework from getting bloated is really hard work.

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