activerecord 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (46) hide show
  1. data/CHANGELOG +33 -0
  2. data/examples/performance.rb +18 -1
  3. data/lib/active_record.rb +3 -3
  4. data/lib/active_record/aggregations.rb +2 -2
  5. data/lib/active_record/association_preload.rb +1 -1
  6. data/lib/active_record/associations.rb +59 -26
  7. data/lib/active_record/associations/association_collection.rb +28 -18
  8. data/lib/active_record/associations/association_proxy.rb +4 -4
  9. data/lib/active_record/associations/belongs_to_association.rb +3 -3
  10. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +10 -13
  11. data/lib/active_record/associations/has_many_through_association.rb +2 -3
  12. data/lib/active_record/associations/has_one_association.rb +6 -6
  13. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  14. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -4
  15. data/lib/active_record/attribute_methods/primary_key.rb +4 -3
  16. data/lib/active_record/autosave_association.rb +7 -7
  17. data/lib/active_record/base.rb +62 -46
  18. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +6 -8
  19. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +2 -2
  20. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +5 -9
  21. data/lib/active_record/connection_adapters/mysql_adapter.rb +7 -7
  22. data/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -2
  23. data/lib/active_record/dynamic_finder_match.rb +20 -17
  24. data/lib/active_record/dynamic_scope_match.rb +6 -15
  25. data/lib/active_record/fixtures.rb +3 -5
  26. data/lib/active_record/locking/optimistic.rb +1 -1
  27. data/lib/active_record/locking/pessimistic.rb +4 -4
  28. data/lib/active_record/nested_attributes.rb +9 -4
  29. data/lib/active_record/persistence.rb +7 -8
  30. data/lib/active_record/railties/databases.rake +7 -7
  31. data/lib/active_record/relation.rb +16 -18
  32. data/lib/active_record/relation/batches.rb +1 -1
  33. data/lib/active_record/relation/calculations.rb +37 -28
  34. data/lib/active_record/relation/finder_methods.rb +19 -19
  35. data/lib/active_record/relation/predicate_builder.rb +3 -1
  36. data/lib/active_record/relation/query_methods.rb +100 -75
  37. data/lib/active_record/relation/spawn_methods.rb +50 -39
  38. data/lib/active_record/serialization.rb +1 -1
  39. data/lib/active_record/session_store.rb +4 -4
  40. data/lib/active_record/transactions.rb +6 -6
  41. data/lib/active_record/validations.rb +1 -1
  42. data/lib/active_record/validations/uniqueness.rb +6 -1
  43. data/lib/active_record/version.rb +1 -1
  44. data/lib/rails/generators/active_record.rb +2 -10
  45. data/lib/rails/generators/active_record/migration.rb +15 -0
  46. metadata +25 -11
@@ -5,9 +5,11 @@ module ActiveRecord
5
5
  def merge(r)
6
6
  merged_relation = clone
7
7
  return merged_relation unless r
8
+ return to_a & r if r.is_a?(Array)
8
9
 
9
- ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - [:joins, :where]).each do |method|
10
+ Relation::ASSOCIATION_METHODS.each do |method|
10
11
  value = r.send(:"#{method}_values")
12
+
11
13
  unless value.empty?
12
14
  if method == :includes
13
15
  merged_relation = merged_relation.includes(value)
@@ -17,26 +19,44 @@ module ActiveRecord
17
19
  end
18
20
  end
19
21
 
20
- merged_relation = merged_relation.joins(r.joins_values)
21
-
22
- merged_wheres = @where_values
22
+ (Relation::MULTI_VALUE_METHODS - [:joins, :where, :order]).each do |method|
23
+ value = r.send(:"#{method}_values")
24
+ merged_relation.send(:"#{method}_values=", merged_relation.send(:"#{method}_values") + value) if value.present?
25
+ end
23
26
 
24
- r.where_values.each do |w|
25
- if w.respond_to?(:operator) && w.operator == :==
26
- merged_wheres = merged_wheres.reject { |p|
27
- p.respond_to?(:operator) && p.operator == :== && p.operand1.name == w.operand1.name
28
- }
27
+ order_value = r.order_values
28
+ if order_value.present?
29
+ if r.reorder_flag
30
+ merged_relation.order_values = order_value
31
+ else
32
+ merged_relation.order_values = merged_relation.order_values + order_value
29
33
  end
34
+ end
30
35
 
31
- merged_wheres += [w]
36
+ merged_relation = merged_relation.joins(r.joins_values)
37
+
38
+ merged_wheres = @where_values + r.where_values
39
+
40
+ unless @where_values.empty?
41
+ # Remove duplicates, last one wins.
42
+ seen = Hash.new { |h,table| h[table] = {} }
43
+ merged_wheres = merged_wheres.reverse.reject { |w|
44
+ nuke = false
45
+ if w.respond_to?(:operator) && w.operator == :==
46
+ name = w.left.name
47
+ table = w.left.relation.name
48
+ nuke = seen[table][name]
49
+ seen[table][name] = true
50
+ end
51
+ nuke
52
+ }.reverse
32
53
  end
33
54
 
34
55
  merged_relation.where_values = merged_wheres
35
56
 
36
57
  Relation::SINGLE_VALUE_METHODS.reject {|m| m == :lock}.each do |method|
37
- unless (value = r.send(:"#{method}_value")).nil?
38
- merged_relation.send(:"#{method}_value=", value)
39
- end
58
+ value = r.send(:"#{method}_value")
59
+ merged_relation.send(:"#{method}_value=", value) unless value.nil?
40
60
  end
41
61
 
42
62
  merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
@@ -52,12 +72,12 @@ module ActiveRecord
52
72
  def except(*skips)
53
73
  result = self.class.new(@klass, table)
54
74
 
55
- (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).each do |method|
56
- result.send(:"#{method}_values=", send(:"#{method}_values")) unless skips.include?(method)
75
+ ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - skips).each do |method|
76
+ result.send(:"#{method}_values=", send(:"#{method}_values"))
57
77
  end
58
78
 
59
- Relation::SINGLE_VALUE_METHODS.each do |method|
60
- result.send(:"#{method}_value=", send(:"#{method}_value")) unless skips.include?(method)
79
+ (Relation::SINGLE_VALUE_METHODS - skips).each do |method|
80
+ result.send(:"#{method}_value=", send(:"#{method}_value"))
61
81
  end
62
82
 
63
83
  result
@@ -66,14 +86,12 @@ module ActiveRecord
66
86
  def only(*onlies)
67
87
  result = self.class.new(@klass, table)
68
88
 
69
- onlies.each do |only|
70
- if (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).include?(only)
71
- result.send(:"#{only}_values=", send(:"#{only}_values"))
72
- elsif Relation::SINGLE_VALUE_METHODS.include?(only)
73
- result.send(:"#{only}_value=", send(:"#{only}_value"))
74
- else
75
- raise "Invalid argument : #{only}"
76
- end
89
+ ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) & onlies).each do |method|
90
+ result.send(:"#{method}_values=", send(:"#{method}_values"))
91
+ end
92
+
93
+ (Relation::SINGLE_VALUE_METHODS & onlies).each do |method|
94
+ result.send(:"#{method}_value=", send(:"#{method}_value"))
77
95
  end
78
96
 
79
97
  result
@@ -87,23 +105,16 @@ module ActiveRecord
87
105
  return relation unless options
88
106
 
89
107
  options.assert_valid_keys(VALID_FIND_OPTIONS)
108
+ finders = options.dup
109
+ finders.delete_if { |key, value| value.nil? }
90
110
 
91
- [:joins, :select, :group, :having, :limit, :offset, :from, :lock].each do |finder|
92
- if value = options[finder]
93
- relation = relation.send(finder, value)
94
- end
95
- end
96
-
97
- relation = relation.readonly(options[:readonly]) if options.key? :readonly
98
-
99
- # Give precedence to newly-applied orders and groups to play nicely with with_scope
100
- [:group, :order].each do |finder|
101
- relation.send("#{finder}_values=", Array.wrap(options[finder]) + relation.send("#{finder}_values")) if options.has_key?(finder)
111
+ ([:joins, :select, :group, :order, :having, :limit, :offset, :from, :lock, :readonly] & finders.keys).each do |finder|
112
+ relation = relation.send(finder, finders[finder])
102
113
  end
103
114
 
104
- relation = relation.where(options[:conditions]) if options.has_key?(:conditions)
105
- relation = relation.includes(options[:include]) if options.has_key?(:include)
106
- relation = relation.extending(options[:extend]) if options.has_key?(:extend)
115
+ relation = relation.where(finders[:conditions]) if options.has_key?(:conditions)
116
+ relation = relation.includes(finders[:include]) if options.has_key?(:include)
117
+ relation = relation.extending(finders[:extend]) if options.has_key?(:extend)
107
118
 
108
119
  relation
109
120
  end
@@ -5,7 +5,7 @@ module ActiveRecord #:nodoc:
5
5
  include ActiveModel::Serializers::JSON
6
6
 
7
7
  def serializable_hash(options = nil)
8
- options ||= {}
8
+ options = options.try(:clone) || {}
9
9
 
10
10
  options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
11
11
  options[:except] |= Array.wrap(self.class.inheritance_column)
@@ -228,7 +228,7 @@ module ActiveRecord
228
228
  @session_id = attributes[:session_id]
229
229
  @data = attributes[:data]
230
230
  @marshaled_data = attributes[:marshaled_data]
231
- @new_record = @marshaled_data.nil?
231
+ @persisted = !@marshaled_data.nil?
232
232
  end
233
233
 
234
234
  # Lazy-unmarshal session state.
@@ -252,8 +252,8 @@ module ActiveRecord
252
252
  marshaled_data = self.class.marshal(data)
253
253
  connect = connection
254
254
 
255
- if @new_record
256
- @new_record = false
255
+ unless @persisted
256
+ @persisted = true
257
257
  connect.update <<-end_sql, 'Create session'
258
258
  INSERT INTO #{table_name} (
259
259
  #{connect.quote_column_name(session_id_column)},
@@ -272,7 +272,7 @@ module ActiveRecord
272
272
  end
273
273
 
274
274
  def destroy
275
- return if @new_record
275
+ return unless @persisted
276
276
 
277
277
  connect = connection
278
278
  connect.delete <<-end_sql, 'Destroy session'
@@ -242,7 +242,7 @@ module ActiveRecord
242
242
  with_transaction_returning_status { super }
243
243
  end
244
244
 
245
- # Reset id and @new_record if the transaction rolls back.
245
+ # Reset id and @persisted if the transaction rolls back.
246
246
  def rollback_active_record_state!
247
247
  remember_transaction_record_state
248
248
  yield
@@ -297,9 +297,9 @@ module ActiveRecord
297
297
  # Save the new record state and id of a record so it can be restored later if a transaction fails.
298
298
  def remember_transaction_record_state #:nodoc
299
299
  @_start_transaction_state ||= {}
300
- unless @_start_transaction_state.include?(:new_record)
300
+ unless @_start_transaction_state.include?(:persisted)
301
301
  @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
302
- @_start_transaction_state[:new_record] = @new_record
302
+ @_start_transaction_state[:persisted] = @persisted
303
303
  end
304
304
  unless @_start_transaction_state.include?(:destroyed)
305
305
  @_start_transaction_state[:destroyed] = @destroyed
@@ -323,7 +323,7 @@ module ActiveRecord
323
323
  restore_state = remove_instance_variable(:@_start_transaction_state)
324
324
  if restore_state
325
325
  @attributes = @attributes.dup if @attributes.frozen?
326
- @new_record = restore_state[:new_record]
326
+ @persisted = restore_state[:persisted]
327
327
  @destroyed = restore_state[:destroyed]
328
328
  if restore_state[:id]
329
329
  self.id = restore_state[:id]
@@ -345,11 +345,11 @@ module ActiveRecord
345
345
  def transaction_include_action?(action) #:nodoc
346
346
  case action
347
347
  when :create
348
- transaction_record_state(:new_record)
348
+ transaction_record_state(:new_record) || !transaction_record_state(:persisted)
349
349
  when :destroy
350
350
  destroyed?
351
351
  when :update
352
- !(transaction_record_state(:new_record) || destroyed?)
352
+ !(transaction_record_state(:new_record) || !transaction_record_state(:persisted) || destroyed?)
353
353
  end
354
354
  end
355
355
  end
@@ -51,7 +51,7 @@ module ActiveRecord
51
51
 
52
52
  # Runs all the specified validations and returns true if no errors were added otherwise false.
53
53
  def valid?(context = nil)
54
- context ||= (new_record? ? :create : :update)
54
+ context ||= (persisted? ? :update : :create)
55
55
  output = super(context)
56
56
 
57
57
  deprecated_callback_method(:validate)
@@ -17,6 +17,11 @@ module ActiveRecord
17
17
  table = finder_class.unscoped
18
18
 
19
19
  table_name = record.class.quoted_table_name
20
+
21
+ if value && record.class.serialized_attributes.key?(attribute.to_s)
22
+ value = YAML.dump value
23
+ end
24
+
20
25
  sql, params = mount_sql_and_params(finder_class, table_name, attribute, value)
21
26
 
22
27
  relation = table.where(sql, *params)
@@ -26,7 +31,7 @@ module ActiveRecord
26
31
  relation = relation.where(scope_item => scope_value)
27
32
  end
28
33
 
29
- unless record.new_record?
34
+ if record.persisted?
30
35
  # TODO : This should be in Arel
31
36
  relation = relation.where("#{record.class.quoted_table_name}.#{record.class.primary_key} <> ?", record.send(:id))
32
37
  end
@@ -3,7 +3,7 @@ module ActiveRecord
3
3
  MAJOR = 3
4
4
  MINOR = 0
5
5
  TINY = 1
6
-
6
+
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
9
9
  end
@@ -1,27 +1,19 @@
1
1
  require 'rails/generators/named_base'
2
2
  require 'rails/generators/migration'
3
3
  require 'rails/generators/active_model'
4
+ require 'rails/generators/active_record/migration'
4
5
  require 'active_record'
5
6
 
6
7
  module ActiveRecord
7
8
  module Generators
8
9
  class Base < Rails::Generators::NamedBase #:nodoc:
9
10
  include Rails::Generators::Migration
11
+ extend ActiveRecord::Generators::Migration
10
12
 
11
13
  # Set the current directory as base for the inherited generators.
12
14
  def self.base_root
13
15
  File.dirname(__FILE__)
14
16
  end
15
-
16
- # Implement the required interface for Rails::Generators::Migration.
17
- def self.next_migration_number(dirname) #:nodoc:
18
- next_migration_number = current_migration_number(dirname) + 1
19
- if ActiveRecord::Base.timestamped_migrations
20
- [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
21
- else
22
- "%.3d" % next_migration_number
23
- end
24
- end
25
17
  end
26
18
  end
27
19
  end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ module Generators
3
+ module Migration
4
+ # Implement the required interface for Rails::Generators::Migration.
5
+ def next_migration_number(dirname) #:nodoc:
6
+ next_migration_number = current_migration_number(dirname) + 1
7
+ if ActiveRecord::Base.timestamped_migrations
8
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
9
+ else
10
+ "%.3d" % next_migration_number
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 3
4
5
  prerelease: false
5
6
  segments:
6
7
  - 3
7
8
  - 0
8
- - 1
9
- version: 3.0.1
9
+ - 2
10
+ version: 3.0.2
10
11
  platform: ruby
11
12
  authors:
12
13
  - David Heinemeier Hansson
@@ -14,58 +15,66 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-10-15 00:00:00 +13:00
18
+ date: 2010-11-15 00:00:00 -06:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: activesupport
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - "="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 3
27
30
  segments:
28
31
  - 3
29
32
  - 0
30
- - 1
31
- version: 3.0.1
33
+ - 2
34
+ version: 3.0.2
32
35
  type: :runtime
33
36
  version_requirements: *id001
34
37
  - !ruby/object:Gem::Dependency
35
38
  name: activemodel
36
39
  prerelease: false
37
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
38
42
  requirements:
39
43
  - - "="
40
44
  - !ruby/object:Gem::Version
45
+ hash: 3
41
46
  segments:
42
47
  - 3
43
48
  - 0
44
- - 1
45
- version: 3.0.1
49
+ - 2
50
+ version: 3.0.2
46
51
  type: :runtime
47
52
  version_requirements: *id002
48
53
  - !ruby/object:Gem::Dependency
49
54
  name: arel
50
55
  prerelease: false
51
56
  requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
52
58
  requirements:
53
59
  - - ~>
54
60
  - !ruby/object:Gem::Version
61
+ hash: 11
55
62
  segments:
56
- - 1
63
+ - 2
57
64
  - 0
58
- - 0
59
- version: 1.0.0
65
+ - 2
66
+ version: 2.0.2
60
67
  type: :runtime
61
68
  version_requirements: *id003
62
69
  - !ruby/object:Gem::Dependency
63
70
  name: tzinfo
64
71
  prerelease: false
65
72
  requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
66
74
  requirements:
67
75
  - - ~>
68
76
  - !ruby/object:Gem::Version
77
+ hash: 61
69
78
  segments:
70
79
  - 0
71
80
  - 3
@@ -165,6 +174,7 @@ files:
165
174
  - lib/active_record.rb
166
175
  - lib/rails/generators/active_record/migration/migration_generator.rb
167
176
  - lib/rails/generators/active_record/migration/templates/migration.rb
177
+ - lib/rails/generators/active_record/migration.rb
168
178
  - lib/rails/generators/active_record/model/model_generator.rb
169
179
  - lib/rails/generators/active_record/model/templates/migration.rb
170
180
  - lib/rails/generators/active_record/model/templates/model.rb
@@ -185,25 +195,29 @@ rdoc_options:
185
195
  require_paths:
186
196
  - lib
187
197
  required_ruby_version: !ruby/object:Gem::Requirement
198
+ none: false
188
199
  requirements:
189
200
  - - ">="
190
201
  - !ruby/object:Gem::Version
202
+ hash: 57
191
203
  segments:
192
204
  - 1
193
205
  - 8
194
206
  - 7
195
207
  version: 1.8.7
196
208
  required_rubygems_version: !ruby/object:Gem::Requirement
209
+ none: false
197
210
  requirements:
198
211
  - - ">="
199
212
  - !ruby/object:Gem::Version
213
+ hash: 3
200
214
  segments:
201
215
  - 0
202
216
  version: "0"
203
217
  requirements: []
204
218
 
205
219
  rubyforge_project: activerecord
206
- rubygems_version: 1.3.6
220
+ rubygems_version: 1.3.7
207
221
  signing_key:
208
222
  specification_version: 3
209
223
  summary: Object-relational mapper framework (part of Rails).