activerecord 4.1.15 → 4.2.0.beta1

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +634 -2176
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +12 -8
  5. data/lib/active_record/associations/association.rb +1 -1
  6. data/lib/active_record/associations/association_scope.rb +53 -21
  7. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  8. data/lib/active_record/associations/builder/association.rb +16 -5
  9. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  10. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
  11. data/lib/active_record/associations/builder/has_one.rb +2 -2
  12. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  13. data/lib/active_record/associations/collection_association.rb +32 -44
  14. data/lib/active_record/associations/collection_proxy.rb +1 -10
  15. data/lib/active_record/associations/has_many_association.rb +60 -14
  16. data/lib/active_record/associations/has_many_through_association.rb +34 -23
  17. data/lib/active_record/associations/has_one_association.rb +0 -1
  18. data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
  19. data/lib/active_record/associations/join_dependency.rb +7 -9
  20. data/lib/active_record/associations/preloader/association.rb +9 -5
  21. data/lib/active_record/associations/preloader/through_association.rb +3 -3
  22. data/lib/active_record/associations/preloader.rb +2 -2
  23. data/lib/active_record/associations/singular_association.rb +16 -1
  24. data/lib/active_record/associations/through_association.rb +6 -22
  25. data/lib/active_record/associations.rb +58 -33
  26. data/lib/active_record/attribute.rb +131 -0
  27. data/lib/active_record/attribute_assignment.rb +19 -11
  28. data/lib/active_record/attribute_decorators.rb +66 -0
  29. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  30. data/lib/active_record/attribute_methods/dirty.rb +85 -42
  31. data/lib/active_record/attribute_methods/primary_key.rb +6 -8
  32. data/lib/active_record/attribute_methods/read.rb +14 -57
  33. data/lib/active_record/attribute_methods/serialization.rb +12 -146
  34. data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
  35. data/lib/active_record/attribute_methods/write.rb +8 -23
  36. data/lib/active_record/attribute_methods.rb +53 -90
  37. data/lib/active_record/attribute_set/builder.rb +32 -0
  38. data/lib/active_record/attribute_set.rb +77 -0
  39. data/lib/active_record/attributes.rb +122 -0
  40. data/lib/active_record/autosave_association.rb +11 -21
  41. data/lib/active_record/base.rb +9 -19
  42. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
  43. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
  44. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
  45. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
  46. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
  47. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
  48. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
  49. data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
  50. data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
  51. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
  52. data/lib/active_record/connection_adapters/column.rb +13 -244
  53. data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
  55. data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
  56. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  57. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  58. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
  59. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
  60. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  61. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  62. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  64. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  66. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  85. data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
  86. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  87. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
  88. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
  89. data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
  90. data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
  91. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  92. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
  93. data/lib/active_record/connection_handling.rb +1 -1
  94. data/lib/active_record/core.rb +119 -22
  95. data/lib/active_record/counter_cache.rb +60 -6
  96. data/lib/active_record/enum.rb +9 -10
  97. data/lib/active_record/errors.rb +27 -26
  98. data/lib/active_record/explain.rb +1 -1
  99. data/lib/active_record/fixtures.rb +52 -45
  100. data/lib/active_record/gem_version.rb +3 -3
  101. data/lib/active_record/inheritance.rb +33 -8
  102. data/lib/active_record/integration.rb +4 -4
  103. data/lib/active_record/locking/optimistic.rb +34 -16
  104. data/lib/active_record/migration/command_recorder.rb +19 -2
  105. data/lib/active_record/migration/join_table.rb +1 -1
  106. data/lib/active_record/migration.rb +22 -32
  107. data/lib/active_record/model_schema.rb +39 -48
  108. data/lib/active_record/nested_attributes.rb +8 -18
  109. data/lib/active_record/persistence.rb +39 -22
  110. data/lib/active_record/query_cache.rb +3 -3
  111. data/lib/active_record/querying.rb +1 -8
  112. data/lib/active_record/railtie.rb +17 -10
  113. data/lib/active_record/railties/databases.rake +47 -42
  114. data/lib/active_record/readonly_attributes.rb +0 -1
  115. data/lib/active_record/reflection.rb +225 -92
  116. data/lib/active_record/relation/batches.rb +0 -2
  117. data/lib/active_record/relation/calculations.rb +28 -32
  118. data/lib/active_record/relation/delegation.rb +1 -1
  119. data/lib/active_record/relation/finder_methods.rb +42 -20
  120. data/lib/active_record/relation/merger.rb +0 -1
  121. data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
  122. data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
  123. data/lib/active_record/relation/predicate_builder.rb +1 -22
  124. data/lib/active_record/relation/query_methods.rb +98 -62
  125. data/lib/active_record/relation/spawn_methods.rb +6 -7
  126. data/lib/active_record/relation.rb +35 -11
  127. data/lib/active_record/result.rb +16 -9
  128. data/lib/active_record/sanitization.rb +8 -1
  129. data/lib/active_record/schema.rb +0 -1
  130. data/lib/active_record/schema_dumper.rb +51 -9
  131. data/lib/active_record/schema_migration.rb +4 -0
  132. data/lib/active_record/scoping/default.rb +5 -4
  133. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  134. data/lib/active_record/statement_cache.rb +79 -5
  135. data/lib/active_record/store.rb +5 -5
  136. data/lib/active_record/tasks/database_tasks.rb +37 -5
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  138. data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
  139. data/lib/active_record/timestamp.rb +9 -7
  140. data/lib/active_record/transactions.rb +35 -21
  141. data/lib/active_record/type/binary.rb +40 -0
  142. data/lib/active_record/type/boolean.rb +19 -0
  143. data/lib/active_record/type/date.rb +46 -0
  144. data/lib/active_record/type/date_time.rb +43 -0
  145. data/lib/active_record/type/decimal.rb +40 -0
  146. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  147. data/lib/active_record/type/float.rb +19 -0
  148. data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
  149. data/lib/active_record/type/integer.rb +23 -0
  150. data/lib/active_record/type/mutable.rb +16 -0
  151. data/lib/active_record/type/numeric.rb +36 -0
  152. data/lib/active_record/type/serialized.rb +51 -0
  153. data/lib/active_record/type/string.rb +36 -0
  154. data/lib/active_record/type/text.rb +11 -0
  155. data/lib/active_record/type/time.rb +26 -0
  156. data/lib/active_record/type/time_value.rb +38 -0
  157. data/lib/active_record/type/type_map.rb +48 -0
  158. data/lib/active_record/type/value.rb +101 -0
  159. data/lib/active_record/type.rb +20 -0
  160. data/lib/active_record/validations/uniqueness.rb +9 -23
  161. data/lib/active_record/validations.rb +21 -16
  162. data/lib/active_record.rb +2 -1
  163. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  164. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  165. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  166. metadata +71 -14
  167. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -67,6 +67,7 @@ module ActiveRecord
67
67
  #
68
68
  def #{name}_values=(values) # def select_values=(values)
69
69
  raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
70
+ check_cached_relation
70
71
  @values[:#{name}] = values # @values[:select] = values
71
72
  end # end
72
73
  CODE
@@ -84,11 +85,22 @@ module ActiveRecord
84
85
  class_eval <<-CODE, __FILE__, __LINE__ + 1
85
86
  def #{name}_value=(value) # def readonly_value=(value)
86
87
  raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
88
+ check_cached_relation
87
89
  @values[:#{name}] = value # @values[:readonly] = value
88
90
  end # end
89
91
  CODE
90
92
  end
91
93
 
94
+ def check_cached_relation # :nodoc:
95
+ if defined?(@arel) && @arel
96
+ @arel = nil
97
+ ActiveSupport::Deprecation.warn <<-WARNING
98
+ Modifying already cached Relation. The cache will be reset.
99
+ Use a cloned Relation to prevent this warning.
100
+ WARNING
101
+ end
102
+ end
103
+
92
104
  def create_with_value # :nodoc:
93
105
  @values[:create_with] || {}
94
106
  end
@@ -173,7 +185,7 @@ module ActiveRecord
173
185
 
174
186
  # Use to indicate that the given +table_names+ are referenced by an SQL string,
175
187
  # and should therefore be JOINed in any query rather than loaded separately.
176
- # This method only works in conjuction with +includes+.
188
+ # This method only works in conjunction with +includes+.
177
189
  # See #includes for more details.
178
190
  #
179
191
  # User.includes(:posts).where("posts.name = 'foo'")
@@ -207,7 +219,7 @@ module ActiveRecord
207
219
  # fields are retrieved:
208
220
  #
209
221
  # Model.select(:field)
210
- # # => [#<Model field:value>]
222
+ # # => [#<Model id: nil, field: "value">]
211
223
  #
212
224
  # Although in the above example it looks as though this method returns an
213
225
  # array, it actually returns a relation object and can have other query
@@ -216,12 +228,12 @@ module ActiveRecord
216
228
  # The argument to the method can also be an array of fields.
217
229
  #
218
230
  # Model.select(:field, :other_field, :and_one_more)
219
- # # => [#<Model field: "value", other_field: "value", and_one_more: "value">]
231
+ # # => [#<Model id: nil, field: "value", other_field: "value", and_one_more: "value">]
220
232
  #
221
233
  # You can also use one or more strings, which will be used unchanged as SELECT fields.
222
234
  #
223
235
  # Model.select('field AS field_one', 'other_field AS field_two')
224
- # # => [#<Model field: "value", other_field: "value">]
236
+ # # => [#<Model id: nil, field: "value", other_field: "value">]
225
237
  #
226
238
  # If an alias was specified, it will be accessible from the resulting objects:
227
239
  #
@@ -229,7 +241,7 @@ module ActiveRecord
229
241
  # # => "value"
230
242
  #
231
243
  # Accessing attributes of an object that do not have fields retrieved by a select
232
- # will throw <tt>ActiveModel::MissingAttributeError</tt>:
244
+ # except +id+ will throw <tt>ActiveModel::MissingAttributeError</tt>:
233
245
  #
234
246
  # Model.select(:field).first.other_field
235
247
  # # => ActiveModel::MissingAttributeError: missing attribute: other_field
@@ -266,6 +278,10 @@ module ActiveRecord
266
278
  #
267
279
  # User.group('name AS grouped_name, age')
268
280
  # => [#<User id: 3, name: "Foo", age: 21, ...>, #<User id: 2, name: "Oscar", age: 21, ...>, #<User id: 5, name: "Foo", age: 23, ...>]
281
+ #
282
+ # Passing in an array of attributes to group by is also supported.
283
+ # User.select([:id, :first_name]).group(:id, :first_name).first(3)
284
+ # => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
269
285
  def group(*args)
270
286
  check_if_method_has_arguments!(:group, args)
271
287
  spawn.group!(*args)
@@ -280,15 +296,6 @@ module ActiveRecord
280
296
 
281
297
  # Allows to specify an order attribute:
282
298
  #
283
- # User.order('name')
284
- # => SELECT "users".* FROM "users" ORDER BY name
285
- #
286
- # User.order('name DESC')
287
- # => SELECT "users".* FROM "users" ORDER BY name DESC
288
- #
289
- # User.order('name DESC, email')
290
- # => SELECT "users".* FROM "users" ORDER BY name DESC, email
291
- #
292
299
  # User.order(:name)
293
300
  # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
294
301
  #
@@ -297,6 +304,15 @@ module ActiveRecord
297
304
  #
298
305
  # User.order(:name, email: :desc)
299
306
  # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
307
+ #
308
+ # User.order('name')
309
+ # => SELECT "users".* FROM "users" ORDER BY name
310
+ #
311
+ # User.order('name DESC')
312
+ # => SELECT "users".* FROM "users" ORDER BY name DESC
313
+ #
314
+ # User.order('name DESC, email')
315
+ # => SELECT "users".* FROM "users" ORDER BY name DESC, email
300
316
  def order(*args)
301
317
  check_if_method_has_arguments!(:order, args)
302
318
  spawn.order!(*args)
@@ -560,18 +576,14 @@ module ActiveRecord
560
576
  end
561
577
  end
562
578
 
563
- def where!(opts = :chain, *rest) # :nodoc:
564
- if opts == :chain
565
- WhereChain.new(self)
566
- else
567
- if Hash === opts
568
- opts = sanitize_forbidden_attributes(opts)
569
- references!(PredicateBuilder.references(opts))
570
- end
571
-
572
- self.where_values += build_where(opts, rest)
573
- self
579
+ def where!(opts, *rest) # :nodoc:
580
+ if Hash === opts
581
+ opts = sanitize_forbidden_attributes(opts)
582
+ references!(PredicateBuilder.references(opts))
574
583
  end
584
+
585
+ self.where_values += build_where(opts, rest)
586
+ self
575
587
  end
576
588
 
577
589
  # Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
@@ -677,11 +689,11 @@ module ActiveRecord
677
689
  # end
678
690
  #
679
691
  def none
680
- where("1=0").extending!(NullRelation)
692
+ extending(NullRelation)
681
693
  end
682
694
 
683
695
  def none! # :nodoc:
684
- where!("1=0").extending!(NullRelation)
696
+ extending!(NullRelation)
685
697
  end
686
698
 
687
699
  # Sets readonly attributes for the returned relation. If value is
@@ -833,7 +845,9 @@ module ActiveRecord
833
845
  end
834
846
 
835
847
  def reverse_order! # :nodoc:
836
- self.reverse_order_value = !reverse_order_value
848
+ orders = order_values.uniq
849
+ orders.reject!(&:blank?)
850
+ self.order_values = reverse_sql_order(orders)
837
851
  self
838
852
  end
839
853
 
@@ -849,25 +863,26 @@ module ActiveRecord
849
863
 
850
864
  build_joins(arel, joins_values.flatten) unless joins_values.empty?
851
865
 
852
- collapse_wheres(arel, (where_values - ['']).uniq)
866
+ collapse_wheres(arel, (where_values - [''])) #TODO: Add uniq with real value comparison / ignore uniqs that have binds
853
867
 
854
868
  arel.having(*having_values.uniq.reject(&:blank?)) unless having_values.empty?
855
869
 
856
870
  arel.take(connection.sanitize_limit(limit_value)) if limit_value
857
871
  arel.skip(offset_value.to_i) if offset_value
858
- arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
872
+
873
+ arel.group(*group_values.uniq.reject(&:blank?)) unless group_values.empty?
859
874
 
860
875
  build_order(arel)
861
876
 
862
- build_select(arel)
877
+ build_select(arel, select_values.uniq)
863
878
 
864
879
  arel.distinct(distinct_value)
865
880
  arel.from(build_from) if from_value
866
881
  arel.lock(lock_value) if lock_value
867
882
 
868
883
  # Reorder bind indexes if joins produced bind values
869
- bvs = arel.bind_values + bind_values
870
- if bvs.any?
884
+ if arel.bind_values.any?
885
+ bvs = arel.bind_values + bind_values
871
886
  arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
872
887
  column = bvs[i].first
873
888
  bp.replace connection.substitute_at(column, i)
@@ -887,8 +902,9 @@ module ActiveRecord
887
902
 
888
903
  case scope
889
904
  when :order
890
- self.reverse_order_value = false
891
905
  result = []
906
+ when :where
907
+ self.bind_values = []
892
908
  else
893
909
  result = [] unless single_val_method
894
910
  end
@@ -939,18 +955,15 @@ module ActiveRecord
939
955
  def build_where(opts, other = [])
940
956
  case opts
941
957
  when String, Array
942
- #TODO: Remove duplication with: /activerecord/lib/active_record/sanitization.rb:113
943
- values = Hash === other.first ? other.first.values : other
944
-
945
- values.grep(ActiveRecord::Relation) do |rel|
946
- self.bind_values += rel.bind_values
947
- end
948
-
949
958
  [@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
950
959
  when Hash
951
960
  opts = PredicateBuilder.resolve_column_aliases(klass, opts)
952
- attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
953
961
 
962
+ bv_len = bind_values.length
963
+ tmp_opts, bind_values = create_binds(opts, bv_len)
964
+ self.bind_values += bind_values
965
+
966
+ attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
954
967
  add_relations_to_bind_values(attributes)
955
968
 
956
969
  PredicateBuilder.build_from_hash(klass, attributes, table)
@@ -959,6 +972,29 @@ module ActiveRecord
959
972
  end
960
973
  end
961
974
 
975
+ def create_binds(opts, idx)
976
+ bindable, non_binds = opts.partition do |column, value|
977
+ case value
978
+ when String, Integer, ActiveRecord::StatementCache::Substitute
979
+ @klass.columns_hash.include? column.to_s
980
+ else
981
+ false
982
+ end
983
+ end
984
+
985
+ new_opts = {}
986
+ binds = []
987
+
988
+ bindable.each_with_index do |(column,value), index|
989
+ binds.push [@klass.columns_hash[column.to_s], value]
990
+ new_opts[column] = connection.substitute_at(column, index + idx)
991
+ end
992
+
993
+ non_binds.each { |column,value| new_opts[column] = value }
994
+
995
+ [new_opts, binds]
996
+ end
997
+
962
998
  def build_from
963
999
  opts, name = from_value
964
1000
  case opts
@@ -1000,33 +1036,29 @@ module ActiveRecord
1000
1036
  join_list
1001
1037
  )
1002
1038
 
1003
- joins = join_dependency.join_constraints stashed_association_joins
1039
+ join_infos = join_dependency.join_constraints stashed_association_joins
1004
1040
 
1005
- joins.each { |join| manager.from(join) }
1041
+ join_infos.each do |info|
1042
+ info.joins.each { |join| manager.from(join) }
1043
+ manager.bind_values.concat info.binds
1044
+ end
1006
1045
 
1007
1046
  manager.join_sources.concat(join_list)
1008
1047
 
1009
1048
  manager
1010
1049
  end
1011
1050
 
1012
- def build_select(arel)
1013
- if select_values.any?
1014
- arel.project(*arel_columns(select_values.uniq))
1051
+ def build_select(arel, selects)
1052
+ if !selects.empty?
1053
+ expanded_select = selects.map do |field|
1054
+ columns_hash.key?(field.to_s) ? arel_table[field] : field
1055
+ end
1056
+ arel.project(*expanded_select)
1015
1057
  else
1016
1058
  arel.project(@klass.arel_table[Arel.star])
1017
1059
  end
1018
1060
  end
1019
1061
 
1020
- def arel_columns(columns)
1021
- columns.map do |field|
1022
- if columns_hash.key?(field.to_s)
1023
- arel_table[field]
1024
- else
1025
- field
1026
- end
1027
- end
1028
- end
1029
-
1030
1062
  def reverse_sql_order(order_query)
1031
1063
  order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
1032
1064
 
@@ -1052,15 +1084,19 @@ module ActiveRecord
1052
1084
  def build_order(arel)
1053
1085
  orders = order_values.uniq
1054
1086
  orders.reject!(&:blank?)
1055
- orders = reverse_sql_order(orders) if reverse_order_value
1056
1087
 
1057
1088
  arel.order(*orders) unless orders.empty?
1058
1089
  end
1059
1090
 
1091
+ VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
1092
+ 'asc', 'desc', 'ASC', 'DESC'] # :nodoc:
1093
+
1060
1094
  def validate_order_args(args)
1061
- args.grep(Hash) do |h|
1062
- unless (h.values - [:asc, :desc]).empty?
1063
- raise ArgumentError, 'Direction should be :asc or :desc'
1095
+ args.each do |arg|
1096
+ next unless arg.is_a?(Hash)
1097
+ arg.each do |_key, value|
1098
+ raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
1099
+ "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
1064
1100
  end
1065
1101
  end
1066
1102
  end
@@ -1082,7 +1118,7 @@ module ActiveRecord
1082
1118
  when Hash
1083
1119
  arg.map { |field, dir|
1084
1120
  field = klass.attribute_alias(field) if klass.attribute_alias?(field)
1085
- table[field].send(dir)
1121
+ table[field].send(dir.downcase)
1086
1122
  }
1087
1123
  else
1088
1124
  arg
@@ -12,7 +12,6 @@ module ActiveRecord
12
12
 
13
13
  # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
14
14
  # Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
15
- #
16
15
  # Post.where(published: true).joins(:comments).merge( Comment.where(spam: false) )
17
16
  # # Performs a single join query with both where conditions.
18
17
  #
@@ -38,14 +37,11 @@ module ActiveRecord
38
37
  end
39
38
 
40
39
  def merge!(other) # :nodoc:
41
- if other.is_a?(Hash)
42
- Relation::HashMerger.new(self, other).merge
43
- elsif other.is_a?(Relation)
44
- Relation::Merger.new(self, other).merge
45
- elsif other.respond_to?(:to_proc)
40
+ if !other.is_a?(Relation) && other.respond_to?(:to_proc)
46
41
  instance_exec(&other)
47
42
  else
48
- raise ArgumentError, "#{other.inspect} is not an ActiveRecord::Relation"
43
+ klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger
44
+ klass.new(self, other).merge
49
45
  end
50
46
  end
51
47
 
@@ -62,6 +58,9 @@ module ActiveRecord
62
58
  # Post.order('id asc').only(:where) # discards the order condition
63
59
  # Post.order('id asc').only(:where, :order) # uses the specified order
64
60
  def only(*onlies)
61
+ if onlies.any? { |o| o == :where }
62
+ onlies << :bind
63
+ end
65
64
  relation_with values.slice(*onlies)
66
65
  end
67
66
 
@@ -1,4 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
+ require 'arel/collectors/bind'
2
3
 
3
4
  module ActiveRecord
4
5
  # = Active Record Relation
@@ -11,6 +12,7 @@ module ActiveRecord
11
12
 
12
13
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
13
14
  :reverse_order, :distinct, :create_with, :uniq]
15
+ INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
14
16
 
15
17
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
16
18
 
@@ -230,6 +232,7 @@ module ActiveRecord
230
232
  # Please see further details in the
231
233
  # {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
232
234
  def explain
235
+ #TODO: Fix for binds.
233
236
  exec_explain(collecting_queries_for_explain { exec_queries })
234
237
  end
235
238
 
@@ -239,6 +242,11 @@ module ActiveRecord
239
242
  @records
240
243
  end
241
244
 
245
+ # Serializes the relation objects Array.
246
+ def encode_with(coder)
247
+ coder.represent_seq(nil, to_a)
248
+ end
249
+
242
250
  def as_json(options = nil) #:nodoc:
243
251
  to_a.as_json(options)
244
252
  end
@@ -330,7 +338,8 @@ module ActiveRecord
330
338
  stmt.wheres = arel.constraints
331
339
  end
332
340
 
333
- @klass.connection.update stmt, 'SQL', bind_values
341
+ bvs = bind_values + arel.bind_values
342
+ @klass.connection.update stmt, 'SQL', bvs
334
343
  end
335
344
 
336
345
  # Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -434,12 +443,21 @@ module ActiveRecord
434
443
  # If you need to destroy dependent associations or call your <tt>before_*</tt> or
435
444
  # +after_destroy+ callbacks, use the +destroy_all+ method instead.
436
445
  #
437
- # If a limit scope is supplied, +delete_all+ raises an ActiveRecord error:
446
+ # If an invalid method is supplied, +delete_all+ raises an ActiveRecord error:
438
447
  #
439
448
  # Post.limit(100).delete_all
440
- # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit scope
449
+ # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
441
450
  def delete_all(conditions = nil)
442
- raise ActiveRecordError.new("delete_all doesn't support limit scope") if self.limit_value
451
+ invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
452
+ if MULTI_VALUE_METHODS.include?(method)
453
+ send("#{method}_values").any?
454
+ else
455
+ send("#{method}_value")
456
+ end
457
+ }
458
+ if invalid_methods.any?
459
+ raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
460
+ end
443
461
 
444
462
  if conditions
445
463
  where(conditions).delete_all
@@ -523,11 +541,11 @@ module ActiveRecord
523
541
  find_with_associations { |rel| relation = rel }
524
542
  end
525
543
 
526
- ast = relation.arel.ast
527
- binds = relation.bind_values.dup
528
- visitor.accept(ast) do
529
- connection.quote(*binds.shift.reverse)
530
- end
544
+ arel = relation.arel
545
+ binds = (arel.bind_values + relation.bind_values).dup
546
+ binds.map! { |bv| connection.quote(*bv.reverse) }
547
+ collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
548
+ collect.substitute_binds(binds).join
531
549
  end
532
550
  end
533
551
 
@@ -544,7 +562,13 @@ module ActiveRecord
544
562
 
545
563
  Hash[equalities.map { |where|
546
564
  name = where.left.name
547
- [name, binds.fetch(name.to_s) { where.right }]
565
+ [name, binds.fetch(name.to_s) {
566
+ case where.right
567
+ when Array then where.right.map(&:val)
568
+ else
569
+ where.right.val
570
+ end
571
+ }]
548
572
  }]
549
573
  end
550
574
 
@@ -608,7 +632,7 @@ module ActiveRecord
608
632
  private
609
633
 
610
634
  def exec_queries
611
- @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
635
+ @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, arel.bind_values + bind_values)
612
636
 
613
637
  preload = preload_values
614
638
  preload += includes_values unless eager_loading?
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  class Result
32
32
  include Enumerable
33
33
 
34
- IDENTITY_TYPE = Class.new { def type_cast(v); v; end }.new # :nodoc:
34
+ IDENTITY_TYPE = Type::Value.new # :nodoc:
35
35
 
36
36
  attr_reader :columns, :rows, :column_types
37
37
 
@@ -42,14 +42,6 @@ module ActiveRecord
42
42
  @column_types = column_types
43
43
  end
44
44
 
45
- def identity_type # :nodoc:
46
- IDENTITY_TYPE
47
- end
48
-
49
- def column_type(name)
50
- @column_types[name] || identity_type
51
- end
52
-
53
45
  def each
54
46
  if block_given?
55
47
  hash_rows.each { |row| yield row }
@@ -82,6 +74,15 @@ module ActiveRecord
82
74
  hash_rows.last
83
75
  end
84
76
 
77
+ def cast_values(type_overrides = {}) # :nodoc:
78
+ types = columns.map { |name| column_type(name, type_overrides) }
79
+ result = rows.map do |values|
80
+ types.zip(values).map { |type, value| type.type_cast_from_database(value) }
81
+ end
82
+
83
+ columns.one? ? result.map!(&:first) : result
84
+ end
85
+
85
86
  def initialize_copy(other)
86
87
  @columns = columns.dup
87
88
  @rows = rows.dup
@@ -91,6 +92,12 @@ module ActiveRecord
91
92
 
92
93
  private
93
94
 
95
+ def column_type(name, type_overrides = {})
96
+ type_overrides.fetch(name) do
97
+ column_types.fetch(name, IDENTITY_TYPE)
98
+ end
99
+ end
100
+
94
101
  def hash_rows
95
102
  @hash_rows ||=
96
103
  begin
@@ -92,7 +92,7 @@ module ActiveRecord
92
92
 
93
93
  table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
94
94
  PredicateBuilder.build_from_hash(self, attrs, table).map { |b|
95
- connection.visitor.accept b
95
+ connection.visitor.compile b
96
96
  }.join(' AND ')
97
97
  end
98
98
  alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
@@ -107,6 +107,13 @@ module ActiveRecord
107
107
  end.join(', ')
108
108
  end
109
109
 
110
+ # Sanitizes a +string+ so that it is safe to use within an SQL
111
+ # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%"
112
+ def sanitize_sql_like(string, escape_character = "\\")
113
+ pattern = Regexp.union(escape_character, "%", "_")
114
+ string.gsub(pattern) { |x| [escape_character, x].join }
115
+ end
116
+
110
117
  # Accepts an array of conditions. The array has each value
111
118
  # sanitized and interpolated into the SQL statement.
112
119
  # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
@@ -1,4 +1,3 @@
1
-
2
1
  module ActiveRecord
3
2
  # = Active Record Schema
4
3
  #
@@ -91,16 +91,17 @@ HEADER
91
91
  end
92
92
 
93
93
  def tables(stream)
94
- @connection.tables.sort.each do |tbl|
95
- next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
96
- case ignored
97
- when String; remove_prefix_and_suffix(tbl) == ignored
98
- when Regexp; remove_prefix_and_suffix(tbl) =~ ignored
99
- else
100
- raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
101
- end
94
+ sorted_tables = @connection.tables.sort
95
+
96
+ sorted_tables.each do |table_name|
97
+ table(table_name, stream) unless ignored?(table_name)
98
+ end
99
+
100
+ # dump foreign keys at the end to make sure all dependent tables exist.
101
+ if @connection.supports_foreign_keys?
102
+ sorted_tables.each do |tbl|
103
+ foreign_keys(tbl, stream)
102
104
  end
103
- table(tbl, stream)
104
105
  end
105
106
  end
106
107
 
@@ -213,8 +214,49 @@ HEADER
213
214
  end
214
215
  end
215
216
 
217
+ def foreign_keys(table, stream)
218
+ if (foreign_keys = @connection.foreign_keys(table)).any?
219
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
220
+ parts = [
221
+ 'add_foreign_key ' + remove_prefix_and_suffix(foreign_key.from_table).inspect,
222
+ remove_prefix_and_suffix(foreign_key.to_table).inspect,
223
+ ]
224
+
225
+ if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
226
+ parts << ('column: ' + foreign_key.column.inspect)
227
+ end
228
+
229
+ if foreign_key.custom_primary_key?
230
+ parts << ('primary_key: ' + foreign_key.primary_key.inspect)
231
+ end
232
+
233
+ if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
234
+ parts << ('name: ' + foreign_key.name.inspect)
235
+ end
236
+
237
+ parts << ('on_update: ' + foreign_key.on_update.inspect) if foreign_key.on_update
238
+ parts << ('on_delete: ' + foreign_key.on_delete.inspect) if foreign_key.on_delete
239
+
240
+ ' ' + parts.join(', ')
241
+ end
242
+
243
+ stream.puts add_foreign_key_statements.sort.join("\n")
244
+ end
245
+ end
246
+
216
247
  def remove_prefix_and_suffix(table)
217
248
  table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
218
249
  end
250
+
251
+ def ignored?(table_name)
252
+ ['schema_migrations', ignore_tables].flatten.any? do |ignored|
253
+ case ignored
254
+ when String; remove_prefix_and_suffix(table_name) == ignored
255
+ when Regexp; remove_prefix_and_suffix(table_name) =~ ignored
256
+ else
257
+ raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
258
+ end
259
+ end
260
+ end
219
261
  end
220
262
  end
@@ -43,6 +43,10 @@ module ActiveRecord
43
43
  def normalize_migration_number(number)
44
44
  "%.3d" % number.to_i
45
45
  end
46
+
47
+ def normalized_versions
48
+ pluck(:version).map { |v| normalize_migration_number v }
49
+ end
46
50
  end
47
51
 
48
52
  def version
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  end
12
12
 
13
13
  module ClassMethods
14
- # Returns a scope for the model without the +default_scope+.
14
+ # Returns a scope for the model without the previously set scopes.
15
15
  #
16
16
  # class Post < ActiveRecord::Base
17
17
  # def self.default_scope
@@ -19,11 +19,12 @@ module ActiveRecord
19
19
  # end
20
20
  # end
21
21
  #
22
- # Post.all # Fires "SELECT * FROM posts WHERE published = true"
23
- # Post.unscoped.all # Fires "SELECT * FROM posts"
22
+ # Post.all # Fires "SELECT * FROM posts WHERE published = true"
23
+ # Post.unscoped.all # Fires "SELECT * FROM posts"
24
+ # Post.where(published: false).unscoped.all # Fires "SELECT * FROM posts"
24
25
  #
25
26
  # This method also accepts a block. All queries inside the block will
26
- # not use the +default_scope+:
27
+ # not use the previously set scopes.
27
28
  #
28
29
  # Post.unscoped {
29
30
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"