activerecord 3.1.10 → 4.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (237) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +1837 -338
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +39 -43
  5. data/examples/performance.rb +51 -20
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +57 -43
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -39
  10. data/lib/active_record/associations/association.rb +71 -85
  11. data/lib/active_record/associations/association_scope.rb +138 -89
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
  14. data/lib/active_record/associations/builder/association.rb +125 -29
  15. data/lib/active_record/associations/builder/belongs_to.rb +91 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +22 -29
  21. data/lib/active_record/associations/collection_association.rb +294 -187
  22. data/lib/active_record/associations/collection_proxy.rb +961 -94
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +118 -23
  25. data/lib/active_record/associations/has_many_through_association.rb +115 -45
  26. data/lib/active_record/associations/has_one_association.rb +57 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -102
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +61 -32
  38. data/lib/active_record/associations/preloader.rb +113 -87
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +37 -19
  41. data/lib/active_record/associations.rb +505 -371
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +212 -0
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +141 -51
  47. data/lib/active_record/attribute_methods/primary_key.rb +87 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +74 -117
  50. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
  52. data/lib/active_record/attribute_methods/write.rb +60 -21
  53. data/lib/active_record/attribute_methods.rb +409 -48
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +279 -232
  58. data/lib/active_record/base.rb +84 -1969
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +422 -243
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +273 -170
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
  75. data/lib/active_record/connection_adapters/column.rb +33 -221
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +445 -902
  114. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +159 -102
  119. data/lib/active_record/dynamic_matchers.rb +140 -0
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +102 -34
  122. data/lib/active_record/explain.rb +38 -0
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +29 -0
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +318 -260
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +247 -0
  129. data/lib/active_record/integration.rb +113 -0
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +80 -52
  133. data/lib/active_record/locking/pessimistic.rb +27 -5
  134. data/lib/active_record/log_subscriber.rb +25 -18
  135. data/lib/active_record/migration/command_recorder.rb +130 -38
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +532 -201
  138. data/lib/active_record/model_schema.rb +342 -0
  139. data/lib/active_record/nested_attributes.rb +229 -139
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +304 -99
  143. data/lib/active_record/query_cache.rb +25 -43
  144. data/lib/active_record/querying.rb +68 -0
  145. data/lib/active_record/railtie.rb +86 -45
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +7 -4
  148. data/lib/active_record/railties/databases.rake +198 -377
  149. data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
  150. data/lib/active_record/readonly_attributes.rb +23 -0
  151. data/lib/active_record/reflection.rb +516 -165
  152. data/lib/active_record/relation/batches.rb +96 -45
  153. data/lib/active_record/relation/calculations.rb +221 -144
  154. data/lib/active_record/relation/delegation.rb +140 -0
  155. data/lib/active_record/relation/finder_methods.rb +362 -243
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -41
  160. data/lib/active_record/relation/query_methods.rb +982 -155
  161. data/lib/active_record/relation/spawn_methods.rb +50 -110
  162. data/lib/active_record/relation.rb +371 -180
  163. data/lib/active_record/result.rb +109 -12
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +191 -0
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +111 -61
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +135 -0
  170. data/lib/active_record/scoping/named.rb +164 -0
  171. data/lib/active_record/scoping.rb +87 -0
  172. data/lib/active_record/serialization.rb +7 -45
  173. data/lib/active_record/serializers/xml_serializer.rb +14 -65
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +205 -0
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +35 -14
  181. data/lib/active_record/transactions.rb +141 -74
  182. data/lib/active_record/translation.rb +22 -0
  183. data/lib/active_record/type/big_integer.rb +13 -0
  184. data/lib/active_record/type/binary.rb +50 -0
  185. data/lib/active_record/type/boolean.rb +31 -0
  186. data/lib/active_record/type/date.rb +50 -0
  187. data/lib/active_record/type/date_time.rb +54 -0
  188. data/lib/active_record/type/decimal.rb +64 -0
  189. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  190. data/lib/active_record/type/decorator.rb +14 -0
  191. data/lib/active_record/type/float.rb +19 -0
  192. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  193. data/lib/active_record/type/integer.rb +59 -0
  194. data/lib/active_record/type/mutable.rb +16 -0
  195. data/lib/active_record/type/numeric.rb +36 -0
  196. data/lib/active_record/type/serialized.rb +62 -0
  197. data/lib/active_record/type/string.rb +40 -0
  198. data/lib/active_record/type/text.rb +11 -0
  199. data/lib/active_record/type/time.rb +26 -0
  200. data/lib/active_record/type/time_value.rb +38 -0
  201. data/lib/active_record/type/type_map.rb +64 -0
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type/value.rb +110 -0
  204. data/lib/active_record/type.rb +23 -0
  205. data/lib/active_record/validations/associated.rb +27 -18
  206. data/lib/active_record/validations/presence.rb +67 -0
  207. data/lib/active_record/validations/uniqueness.rb +125 -66
  208. data/lib/active_record/validations.rb +37 -30
  209. data/lib/active_record/version.rb +5 -7
  210. data/lib/active_record.rb +80 -25
  211. data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
  212. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  213. data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
  214. data/lib/rails/generators/active_record/migration.rb +11 -8
  215. data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
  216. data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
  217. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  218. data/lib/rails/generators/active_record.rb +3 -11
  219. metadata +132 -53
  220. data/examples/associations.png +0 -0
  221. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
  222. data/lib/active_record/associations/join_helper.rb +0 -55
  223. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
  226. data/lib/active_record/dynamic_finder_match.rb +0 -56
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/identity_map.rb +0 -163
  229. data/lib/active_record/named_scope.rb +0 -200
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -358
  232. data/lib/active_record/test_case.rb +0 -69
  233. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
  234. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  235. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  236. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  237. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -0,0 +1,53 @@
1
+ require 'active_record/scoping/default'
2
+ require 'active_record/scoping/named'
3
+ require 'active_record/base'
4
+
5
+ module ActiveRecord
6
+ class SchemaMigration < ActiveRecord::Base
7
+ class << self
8
+ def primary_key
9
+ nil
10
+ end
11
+
12
+ def table_name
13
+ "#{table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
14
+ end
15
+
16
+ def index_name
17
+ "#{table_name_prefix}unique_#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
18
+ end
19
+
20
+ def table_exists?
21
+ connection.table_exists?(table_name)
22
+ end
23
+
24
+ def create_table(limit=nil)
25
+ unless table_exists?
26
+ version_options = {null: false}
27
+ version_options[:limit] = limit if limit
28
+
29
+ connection.create_table(table_name, id: false) do |t|
30
+ t.column :version, :string, version_options
31
+ end
32
+ connection.add_index table_name, :version, unique: true, name: index_name
33
+ end
34
+ end
35
+
36
+ def drop_table
37
+ connection.drop_table table_name if table_exists?
38
+ end
39
+
40
+ def normalize_migration_number(number)
41
+ "%.3d" % number.to_i
42
+ end
43
+
44
+ def normalized_versions
45
+ pluck(:version).map { |v| normalize_migration_number v }
46
+ end
47
+ end
48
+
49
+ def version
50
+ super.to_i
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,135 @@
1
+ module ActiveRecord
2
+ module Scoping
3
+ module Default
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # Stores the default scope for the class.
8
+ class_attribute :default_scopes, instance_writer: false, instance_predicate: false
9
+
10
+ self.default_scopes = []
11
+ end
12
+
13
+ module ClassMethods
14
+ # Returns a scope for the model without the previously set scopes.
15
+ #
16
+ # class Post < ActiveRecord::Base
17
+ # def self.default_scope
18
+ # where published: true
19
+ # end
20
+ # end
21
+ #
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"
25
+ #
26
+ # This method also accepts a block. All queries inside the block will
27
+ # not use the previously set scopes.
28
+ #
29
+ # Post.unscoped {
30
+ # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
31
+ # }
32
+ def unscoped
33
+ block_given? ? relation.scoping { yield } : relation
34
+ end
35
+
36
+ def before_remove_const #:nodoc:
37
+ self.current_scope = nil
38
+ end
39
+
40
+ protected
41
+
42
+ # Use this macro in your model to set a default scope for all operations on
43
+ # the model.
44
+ #
45
+ # class Article < ActiveRecord::Base
46
+ # default_scope { where(published: true) }
47
+ # end
48
+ #
49
+ # Article.all # => SELECT * FROM articles WHERE published = true
50
+ #
51
+ # The +default_scope+ is also applied while creating/building a record.
52
+ # It is not applied while updating a record.
53
+ #
54
+ # Article.new.published # => true
55
+ # Article.create.published # => true
56
+ #
57
+ # (You can also pass any object which responds to +call+ to the
58
+ # +default_scope+ macro, and it will be called when building the
59
+ # default scope.)
60
+ #
61
+ # If you use multiple +default_scope+ declarations in your model then
62
+ # they will be merged together:
63
+ #
64
+ # class Article < ActiveRecord::Base
65
+ # default_scope { where(published: true) }
66
+ # default_scope { where(rating: 'G') }
67
+ # end
68
+ #
69
+ # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
70
+ #
71
+ # This is also the case with inheritance and module includes where the
72
+ # parent or module defines a +default_scope+ and the child or including
73
+ # class defines a second one.
74
+ #
75
+ # If you need to do more complex things with a default scope, you can
76
+ # alternatively define it as a class method:
77
+ #
78
+ # class Article < ActiveRecord::Base
79
+ # def self.default_scope
80
+ # # Should return a scope, you can call 'super' here etc.
81
+ # end
82
+ # end
83
+ def default_scope(scope = nil)
84
+ scope = Proc.new if block_given?
85
+
86
+ if scope.is_a?(Relation) || !scope.respond_to?(:call)
87
+ raise ArgumentError,
88
+ "Support for calling #default_scope without a block is removed. For example instead " \
89
+ "of `default_scope where(color: 'red')`, please use " \
90
+ "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
91
+ "self.default_scope.)"
92
+ end
93
+
94
+ self.default_scopes += [scope]
95
+ end
96
+
97
+ def build_default_scope(base_rel = relation) # :nodoc:
98
+ return if abstract_class?
99
+ if !Base.is_a?(method(:default_scope).owner)
100
+ # The user has defined their own default scope method, so call that
101
+ evaluate_default_scope { default_scope }
102
+ elsif default_scopes.any?
103
+ evaluate_default_scope do
104
+ default_scopes.inject(base_rel) do |default_scope, scope|
105
+ default_scope.merge(base_rel.scoping { scope.call })
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def ignore_default_scope? # :nodoc:
112
+ ScopeRegistry.value_for(:ignore_default_scope, self)
113
+ end
114
+
115
+ def ignore_default_scope=(ignore) # :nodoc:
116
+ ScopeRegistry.set_value_for(:ignore_default_scope, self, ignore)
117
+ end
118
+
119
+ # The ignore_default_scope flag is used to prevent an infinite recursion
120
+ # situation where a default scope references a scope which has a default
121
+ # scope which references a scope...
122
+ def evaluate_default_scope # :nodoc:
123
+ return if ignore_default_scope?
124
+
125
+ begin
126
+ self.ignore_default_scope = true
127
+ yield
128
+ ensure
129
+ self.ignore_default_scope = false
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,164 @@
1
+ require 'active_support/core_ext/array'
2
+ require 'active_support/core_ext/hash/except'
3
+ require 'active_support/core_ext/kernel/singleton_class'
4
+
5
+ module ActiveRecord
6
+ # = Active Record \Named \Scopes
7
+ module Scoping
8
+ module Named
9
+ extend ActiveSupport::Concern
10
+
11
+ module ClassMethods
12
+ # Returns an <tt>ActiveRecord::Relation</tt> scope object.
13
+ #
14
+ # posts = Post.all
15
+ # posts.size # Fires "select count(*) from posts" and returns the count
16
+ # posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects
17
+ #
18
+ # fruits = Fruit.all
19
+ # fruits = fruits.where(color: 'red') if options[:red_only]
20
+ # fruits = fruits.limit(10) if limited?
21
+ #
22
+ # You can define a scope that applies to all finders using
23
+ # <tt>ActiveRecord::Base.default_scope</tt>.
24
+ def all
25
+ if current_scope
26
+ current_scope.clone
27
+ else
28
+ default_scoped
29
+ end
30
+ end
31
+
32
+ def default_scoped # :nodoc:
33
+ relation.merge(build_default_scope)
34
+ end
35
+
36
+ # Collects attributes from scopes that should be applied when creating
37
+ # an AR instance for the particular class this is called on.
38
+ def scope_attributes # :nodoc:
39
+ all.scope_for_create
40
+ end
41
+
42
+ # Are there default attributes associated with this scope?
43
+ def scope_attributes? # :nodoc:
44
+ current_scope || default_scopes.any?
45
+ end
46
+
47
+ # Adds a class method for retrieving and querying objects. A \scope
48
+ # represents a narrowing of a database query, such as
49
+ # <tt>where(color: :red).select('shirts.*').includes(:washing_instructions)</tt>.
50
+ #
51
+ # class Shirt < ActiveRecord::Base
52
+ # scope :red, -> { where(color: 'red') }
53
+ # scope :dry_clean_only, -> { joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true) }
54
+ # end
55
+ #
56
+ # The above calls to +scope+ define class methods <tt>Shirt.red</tt> and
57
+ # <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, in effect,
58
+ # represents the query <tt>Shirt.where(color: 'red')</tt>.
59
+ #
60
+ # You should always pass a callable object to the scopes defined
61
+ # with +scope+. This ensures that the scope is re-evaluated each
62
+ # time it is called.
63
+ #
64
+ # Note that this is simply 'syntactic sugar' for defining an actual
65
+ # class method:
66
+ #
67
+ # class Shirt < ActiveRecord::Base
68
+ # def self.red
69
+ # where(color: 'red')
70
+ # end
71
+ # end
72
+ #
73
+ # Unlike <tt>Shirt.find(...)</tt>, however, the object returned by
74
+ # <tt>Shirt.red</tt> is not an Array; it resembles the association object
75
+ # constructed by a +has_many+ declaration. For instance, you can invoke
76
+ # <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
77
+ # <tt>Shirt.red.where(size: 'small')</tt>. Also, just as with the
78
+ # association objects, named \scopes act like an Array, implementing
79
+ # Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>,
80
+ # and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if
81
+ # <tt>Shirt.red</tt> really was an Array.
82
+ #
83
+ # These named \scopes are composable. For instance,
84
+ # <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are
85
+ # both red and dry clean only. Nested finds and calculations also work
86
+ # with these compositions: <tt>Shirt.red.dry_clean_only.count</tt>
87
+ # returns the number of garments for which these criteria obtain.
88
+ # Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
89
+ #
90
+ # All scopes are available as class methods on the ActiveRecord::Base
91
+ # descendant upon which the \scopes were defined. But they are also
92
+ # available to +has_many+ associations. If,
93
+ #
94
+ # class Person < ActiveRecord::Base
95
+ # has_many :shirts
96
+ # end
97
+ #
98
+ # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of
99
+ # Elton's red, dry clean only shirts.
100
+ #
101
+ # \Named scopes can also have extensions, just as with +has_many+
102
+ # declarations:
103
+ #
104
+ # class Shirt < ActiveRecord::Base
105
+ # scope :red, -> { where(color: 'red') } do
106
+ # def dom_id
107
+ # 'red_shirts'
108
+ # end
109
+ # end
110
+ # end
111
+ #
112
+ # Scopes can also be used while creating/building a record.
113
+ #
114
+ # class Article < ActiveRecord::Base
115
+ # scope :published, -> { where(published: true) }
116
+ # end
117
+ #
118
+ # Article.published.new.published # => true
119
+ # Article.published.create.published # => true
120
+ #
121
+ # \Class methods on your model are automatically available
122
+ # on scopes. Assuming the following setup:
123
+ #
124
+ # class Article < ActiveRecord::Base
125
+ # scope :published, -> { where(published: true) }
126
+ # scope :featured, -> { where(featured: true) }
127
+ #
128
+ # def self.latest_article
129
+ # order('published_at desc').first
130
+ # end
131
+ #
132
+ # def self.titles
133
+ # pluck(:title)
134
+ # end
135
+ # end
136
+ #
137
+ # We are able to call the methods like this:
138
+ #
139
+ # Article.published.featured.latest_article
140
+ # Article.featured.titles
141
+ def scope(name, body, &block)
142
+ unless body.respond_to?(:call)
143
+ raise ArgumentError, 'The scope body needs to be callable.'
144
+ end
145
+
146
+ if dangerous_class_method?(name)
147
+ raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
148
+ "on the model \"#{self.name}\", but Active Record already defined " \
149
+ "a class method with the same name."
150
+ end
151
+
152
+ extension = Module.new(&block) if block
153
+
154
+ singleton_class.send(:define_method, name) do |*args|
155
+ scope = all.scoping { body.call(*args) }
156
+ scope = scope.extending(extension) if extension
157
+
158
+ scope || all
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,87 @@
1
+ require 'active_support/per_thread_registry'
2
+
3
+ module ActiveRecord
4
+ module Scoping
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include Default
9
+ include Named
10
+ end
11
+
12
+ module ClassMethods
13
+ def current_scope #:nodoc:
14
+ ScopeRegistry.value_for(:current_scope, base_class.to_s)
15
+ end
16
+
17
+ def current_scope=(scope) #:nodoc:
18
+ ScopeRegistry.set_value_for(:current_scope, base_class.to_s, scope)
19
+ end
20
+ end
21
+
22
+ def populate_with_current_scope_attributes
23
+ return unless self.class.scope_attributes?
24
+
25
+ self.class.scope_attributes.each do |att,value|
26
+ send("#{att}=", value) if respond_to?("#{att}=")
27
+ end
28
+ end
29
+
30
+ def initialize_internals_callback
31
+ super
32
+ populate_with_current_scope_attributes
33
+ end
34
+
35
+ # This class stores the +:current_scope+ and +:ignore_default_scope+ values
36
+ # for different classes. The registry is stored as a thread local, which is
37
+ # accessed through +ScopeRegistry.current+.
38
+ #
39
+ # This class allows you to store and get the scope values on different
40
+ # classes and different types of scopes. For example, if you are attempting
41
+ # to get the current_scope for the +Board+ model, then you would use the
42
+ # following code:
43
+ #
44
+ # registry = ActiveRecord::Scoping::ScopeRegistry
45
+ # registry.set_value_for(:current_scope, "Board", some_new_scope)
46
+ #
47
+ # Now when you run:
48
+ #
49
+ # registry.value_for(:current_scope, "Board")
50
+ #
51
+ # You will obtain whatever was defined in +some_new_scope+. The +value_for+
52
+ # and +set_value_for+ methods are delegated to the current +ScopeRegistry+
53
+ # object, so the above example code can also be called as:
54
+ #
55
+ # ActiveRecord::Scoping::ScopeRegistry.set_value_for(:current_scope,
56
+ # "Board", some_new_scope)
57
+ class ScopeRegistry # :nodoc:
58
+ extend ActiveSupport::PerThreadRegistry
59
+
60
+ VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope]
61
+
62
+ def initialize
63
+ @registry = Hash.new { |hash, key| hash[key] = {} }
64
+ end
65
+
66
+ # Obtains the value for a given +scope_name+ and +variable_name+.
67
+ def value_for(scope_type, variable_name)
68
+ raise_invalid_scope_type!(scope_type)
69
+ @registry[scope_type][variable_name]
70
+ end
71
+
72
+ # Sets the +value+ for a given +scope_type+ and +variable_name+.
73
+ def set_value_for(scope_type, variable_name, value)
74
+ raise_invalid_scope_type!(scope_type)
75
+ @registry[scope_type][variable_name] = value
76
+ end
77
+
78
+ private
79
+
80
+ def raise_invalid_scope_type!(scope_type)
81
+ if !VALID_SCOPE_TYPES.include?(scope_type)
82
+ raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -4,56 +4,18 @@ module ActiveRecord #:nodoc:
4
4
  extend ActiveSupport::Concern
5
5
  include ActiveModel::Serializers::JSON
6
6
 
7
+ included do
8
+ self.include_root_in_json = false
9
+ end
10
+
7
11
  def serializable_hash(options = nil)
8
12
  options = options.try(:clone) || {}
9
13
 
10
- options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
11
- options[:except] |= Array.wrap(self.class.inheritance_column)
12
-
13
- hash = super(options)
14
+ options[:except] = Array(options[:except]).map { |n| n.to_s }
15
+ options[:except] |= Array(self.class.inheritance_column)
14
16
 
15
- serializable_add_includes(options) do |association, records, opts|
16
- hash[association] = records.is_a?(Enumerable) ?
17
- records.map { |r| r.serializable_hash(opts) } :
18
- records.serializable_hash(opts)
19
- end
20
-
21
- hash
17
+ super(options)
22
18
  end
23
-
24
- private
25
- # Add associations specified via the <tt>:include</tt> option.
26
- #
27
- # Expects a block that takes as arguments:
28
- # +association+ - name of the association
29
- # +records+ - the association record(s) to be serialized
30
- # +opts+ - options for the association records
31
- def serializable_add_includes(options = {})
32
- return unless include_associations = options.delete(:include)
33
-
34
- base_only_or_except = { :except => options[:except],
35
- :only => options[:only] }
36
-
37
- include_has_options = include_associations.is_a?(Hash)
38
- associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
39
-
40
- associations.each do |association|
41
- records = case self.class.reflect_on_association(association).macro
42
- when :has_many, :has_and_belongs_to_many
43
- send(association).to_a
44
- when :has_one, :belongs_to
45
- send(association)
46
- end
47
-
48
- if records
49
- association_options = include_has_options ? include_associations[association] : base_only_or_except
50
- opts = options.merge(association_options)
51
- yield(association, records, opts)
52
- end
53
- end
54
-
55
- options[:include] = include_associations
56
- end
57
19
  end
58
20
  end
59
21
 
@@ -1,4 +1,3 @@
1
- require 'active_support/core_ext/array/wrap'
2
1
  require 'active_support/core_ext/hash/conversions'
3
2
 
4
3
  module ActiveRecord #:nodoc:
@@ -19,8 +18,8 @@ module ActiveRecord #:nodoc:
19
18
  # <id type="integer">1</id>
20
19
  # <approved type="boolean">false</approved>
21
20
  # <replies-count type="integer">0</replies-count>
22
- # <bonus-time type="datetime">2000-01-01T08:28:00+12:00</bonus-time>
23
- # <written-on type="datetime">2003-07-16T09:28:00+1200</written-on>
21
+ # <bonus-time type="dateTime">2000-01-01T08:28:00+12:00</bonus-time>
22
+ # <written-on type="dateTime">2003-07-16T09:28:00+1200</written-on>
24
23
  # <content>Have a nice day</content>
25
24
  # <author-email-address>david@loudthinking.com</author-email-address>
26
25
  # <parent-id></parent-id>
@@ -37,7 +36,7 @@ module ActiveRecord #:nodoc:
37
36
  #
38
37
  # For instance:
39
38
  #
40
- # topic.to_xml(:skip_instruct => true, :except => [ :id, :bonus_time, :written_on, :replies_count ])
39
+ # topic.to_xml(skip_instruct: true, except: [ :id, :bonus_time, :written_on, :replies_count ])
41
40
  #
42
41
  # <topic>
43
42
  # <title>The First Topic</title>
@@ -51,7 +50,7 @@ module ActiveRecord #:nodoc:
51
50
  #
52
51
  # To include first level associations use <tt>:include</tt>:
53
52
  #
54
- # firm.to_xml :include => [ :account, :clients ]
53
+ # firm.to_xml include: [ :account, :clients ]
55
54
  #
56
55
  # <?xml version="1.0" encoding="UTF-8"?>
57
56
  # <firm>
@@ -75,14 +74,14 @@ module ActiveRecord #:nodoc:
75
74
  # </firm>
76
75
  #
77
76
  # Additionally, the record being serialized will be passed to a Proc's second
78
- # parameter. This allows for ad hoc additions to the resultant document that
77
+ # parameter. This allows for ad hoc additions to the resultant document that
79
78
  # incorporate the context of the record being serialized. And by leveraging the
80
79
  # closure created by a Proc, to_xml can be used to add elements that normally fall
81
80
  # outside of the scope of the model -- for example, generating and appending URLs
82
81
  # associated with models.
83
82
  #
84
83
  # proc = Proc.new { |options, record| options[:builder].tag!('name-reverse', record.name.reverse) }
85
- # firm.to_xml :procs => [ proc ]
84
+ # firm.to_xml procs: [ proc ]
86
85
  #
87
86
  # <firm>
88
87
  # # ... normal attributes as shown above ...
@@ -91,7 +90,7 @@ module ActiveRecord #:nodoc:
91
90
  #
92
91
  # To include deeper levels of associations pass a hash like this:
93
92
  #
94
- # firm.to_xml :include => {:account => {}, :clients => {:include => :address}}
93
+ # firm.to_xml include: {account: {}, clients: {include: :address}}
95
94
  # <?xml version="1.0" encoding="UTF-8"?>
96
95
  # <firm>
97
96
  # <id type="integer">1</id>
@@ -121,7 +120,7 @@ module ActiveRecord #:nodoc:
121
120
  #
122
121
  # To include any methods on the model being called use <tt>:methods</tt>:
123
122
  #
124
- # firm.to_xml :methods => [ :calculated_earnings, :real_earnings ]
123
+ # firm.to_xml methods: [ :calculated_earnings, :real_earnings ]
125
124
  #
126
125
  # <firm>
127
126
  # # ... normal attributes as shown above ...
@@ -133,7 +132,7 @@ module ActiveRecord #:nodoc:
133
132
  # modified version of the options hash that was given to +to_xml+:
134
133
  #
135
134
  # proc = Proc.new { |options| options[:builder].tag!('abc', 'def') }
136
- # firm.to_xml :procs => [ proc ]
135
+ # firm.to_xml procs: [ proc ]
137
136
  #
138
137
  # <firm>
139
138
  # # ... normal attributes as shown above ...
@@ -163,8 +162,9 @@ module ActiveRecord #:nodoc:
163
162
  #
164
163
  # class IHaveMyOwnXML < ActiveRecord::Base
165
164
  # def to_xml(options = {})
165
+ # require 'builder'
166
166
  # options[:indent] ||= 2
167
- # xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
167
+ # xml = options[:builder] ||= ::Builder::XmlMarkup.new(indent: options[:indent])
168
168
  # xml.instruct! unless options[:skip_instruct]
169
169
  # xml.level_one do
170
170
  # xml.tag!(:second_level, 'content')
@@ -177,63 +177,12 @@ module ActiveRecord #:nodoc:
177
177
  end
178
178
 
179
179
  class XmlSerializer < ActiveModel::Serializers::Xml::Serializer #:nodoc:
180
- def initialize(*args)
181
- super
182
- options[:except] |= Array.wrap(@serializable.class.inheritance_column)
183
- end
184
-
185
- def add_extra_behavior
186
- add_includes
187
- end
188
-
189
- def add_includes
190
- procs = options.delete(:procs)
191
- @serializable.send(:serializable_add_includes, options) do |association, records, opts|
192
- add_associations(association, records, opts)
193
- end
194
- options[:procs] = procs
195
- end
196
-
197
- # TODO This can likely be cleaned up to simple use ActiveSupport::XmlMini.to_tag as well.
198
- def add_associations(association, records, opts)
199
- association_name = association.to_s.singularize
200
- merged_options = options.merge(opts).merge!(:root => association_name, :skip_instruct => true)
201
-
202
- if records.is_a?(Enumerable)
203
- tag = ActiveSupport::XmlMini.rename_key(association.to_s, options)
204
- type = options[:skip_types] ? { } : {:type => "array"}
205
-
206
- if records.empty?
207
- @builder.tag!(tag, type)
208
- else
209
- @builder.tag!(tag, type) do
210
- records.each do |record|
211
- if options[:skip_types]
212
- record_type = {}
213
- else
214
- record_class = (record.class.to_s.underscore == association_name) ? nil : record.class.name
215
- record_type = {:type => record_class}
216
- end
217
-
218
- record.to_xml merged_options.merge(record_type)
219
- end
220
- end
221
- end
222
- elsif record = @serializable.send(association)
223
- record.to_xml(merged_options)
224
- end
225
- end
226
-
227
180
  class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc:
228
181
  def compute_type
229
182
  klass = @serializable.class
230
- type = if klass.serialized_attributes.key?(name)
231
- super
232
- elsif klass.columns_hash.key?(name)
233
- klass.columns_hash[name].type
234
- else
235
- NilClass
236
- end
183
+ column = klass.columns_hash[name] || Type::Value.new
184
+
185
+ type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name] || column.type
237
186
 
238
187
  { :text => :string,
239
188
  :time => :datetime }[type] || type