activerecord 4.2.0 → 5.0.0

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1537 -789
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +16 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +23 -9
  11. data/lib/active_record/associations/association_scope.rb +74 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +26 -29
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +12 -20
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +61 -33
  21. data/lib/active_record/associations/collection_proxy.rb +81 -35
  22. data/lib/active_record/associations/foreign_association.rb +11 -0
  23. data/lib/active_record/associations/has_many_association.rb +21 -57
  24. data/lib/active_record/associations/has_many_through_association.rb +15 -45
  25. data/lib/active_record/associations/has_one_association.rb +13 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +37 -21
  28. data/lib/active_record/associations/preloader/association.rb +51 -53
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +18 -8
  34. data/lib/active_record/associations/singular_association.rb +8 -8
  35. data/lib/active_record/associations/through_association.rb +22 -9
  36. data/lib/active_record/associations.rb +321 -212
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +79 -15
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +51 -81
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +37 -15
  52. data/lib/active_record/attribute_set.rb +34 -3
  53. data/lib/active_record/attributes.rb +199 -73
  54. data/lib/active_record/autosave_association.rb +73 -25
  55. data/lib/active_record/base.rb +35 -27
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  101. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  103. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +38 -15
  121. data/lib/active_record/core.rb +109 -114
  122. data/lib/active_record/counter_cache.rb +14 -25
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +115 -79
  125. data/lib/active_record/errors.rb +88 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +2 -2
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +84 -46
  130. data/lib/active_record/gem_version.rb +2 -2
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +27 -25
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration/command_recorder.rb +59 -18
  140. data/lib/active_record/migration/compatibility.rb +126 -0
  141. data/lib/active_record/migration.rb +372 -114
  142. data/lib/active_record/model_schema.rb +128 -38
  143. data/lib/active_record/nested_attributes.rb +71 -32
  144. data/lib/active_record/no_touching.rb +1 -1
  145. data/lib/active_record/null_relation.rb +16 -8
  146. data/lib/active_record/persistence.rb +124 -80
  147. data/lib/active_record/query_cache.rb +15 -18
  148. data/lib/active_record/querying.rb +10 -9
  149. data/lib/active_record/railtie.rb +28 -19
  150. data/lib/active_record/railties/controller_runtime.rb +1 -1
  151. data/lib/active_record/railties/databases.rake +67 -51
  152. data/lib/active_record/readonly_attributes.rb +1 -1
  153. data/lib/active_record/reflection.rb +318 -139
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  155. data/lib/active_record/relation/batches.rb +139 -34
  156. data/lib/active_record/relation/calculations.rb +80 -102
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +167 -97
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +38 -41
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  166. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  167. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  168. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  169. data/lib/active_record/relation/predicate_builder.rb +124 -82
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +323 -257
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +11 -10
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/relation.rb +176 -115
  177. data/lib/active_record/result.rb +4 -3
  178. data/lib/active_record/runtime_registry.rb +1 -1
  179. data/lib/active_record/sanitization.rb +95 -66
  180. data/lib/active_record/schema.rb +26 -22
  181. data/lib/active_record/schema_dumper.rb +62 -38
  182. data/lib/active_record/schema_migration.rb +11 -17
  183. data/lib/active_record/scoping/default.rb +24 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/scoping.rb +32 -15
  186. data/lib/active_record/secure_token.rb +38 -0
  187. data/lib/active_record/serialization.rb +2 -4
  188. data/lib/active_record/statement_cache.rb +16 -14
  189. data/lib/active_record/store.rb +8 -3
  190. data/lib/active_record/suppressor.rb +58 -0
  191. data/lib/active_record/table_metadata.rb +68 -0
  192. data/lib/active_record/tasks/database_tasks.rb +59 -42
  193. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
  194. data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
  195. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  196. data/lib/active_record/timestamp.rb +20 -9
  197. data/lib/active_record/touch_later.rb +58 -0
  198. data/lib/active_record/transactions.rb +159 -67
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -41
  201. data/lib/active_record/type/date_time.rb +2 -38
  202. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  203. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  204. data/lib/active_record/type/internal/timezone.rb +15 -0
  205. data/lib/active_record/type/serialized.rb +21 -14
  206. data/lib/active_record/type/time.rb +10 -16
  207. data/lib/active_record/type/type_map.rb +4 -4
  208. data/lib/active_record/type.rb +66 -17
  209. data/lib/active_record/type_caster/connection.rb +29 -0
  210. data/lib/active_record/type_caster/map.rb +19 -0
  211. data/lib/active_record/type_caster.rb +7 -0
  212. data/lib/active_record/validations/absence.rb +23 -0
  213. data/lib/active_record/validations/associated.rb +10 -3
  214. data/lib/active_record/validations/length.rb +24 -0
  215. data/lib/active_record/validations/presence.rb +11 -12
  216. data/lib/active_record/validations/uniqueness.rb +29 -18
  217. data/lib/active_record/validations.rb +33 -32
  218. data/lib/active_record.rb +9 -2
  219. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  220. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
  221. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
  222. data/lib/rails/generators/active_record/migration.rb +7 -0
  223. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  224. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  225. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  226. metadata +60 -34
  227. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  228. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  229. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  231. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  232. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  233. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  234. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  235. data/lib/active_record/type/big_integer.rb +0 -13
  236. data/lib/active_record/type/binary.rb +0 -50
  237. data/lib/active_record/type/boolean.rb +0 -30
  238. data/lib/active_record/type/decimal.rb +0 -40
  239. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  240. data/lib/active_record/type/decorator.rb +0 -14
  241. data/lib/active_record/type/float.rb +0 -19
  242. data/lib/active_record/type/integer.rb +0 -55
  243. data/lib/active_record/type/mutable.rb +0 -16
  244. data/lib/active_record/type/numeric.rb +0 -36
  245. data/lib/active_record/type/string.rb +0 -36
  246. data/lib/active_record/type/text.rb +0 -11
  247. data/lib/active_record/type/time_value.rb +0 -38
  248. data/lib/active_record/type/unsigned_integer.rb +0 -15
  249. data/lib/active_record/type/value.rb +0 -101
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  class DatabaseAlreadyExists < StandardError; end # :nodoc:
6
6
  class DatabaseNotSupported < StandardError; end # :nodoc:
7
7
 
8
- # <tt>ActiveRecord::Tasks::DatabaseTasks</tt> is a utility class, which encapsulates
8
+ # ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
9
9
  # logic behind common tasks used to manage database and migrations.
10
10
  #
11
11
  # The tasks defined here are used with Rake tasks provided by Active Record.
@@ -18,15 +18,15 @@ module ActiveRecord
18
18
  #
19
19
  # The possible config values are:
20
20
  #
21
- # * +env+: current environment (like Rails.env).
22
- # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
23
- # * +db_dir+: your +db+ directory.
24
- # * +fixtures_path+: a path to fixtures directory.
25
- # * +migrations_paths+: a list of paths to directories with migrations.
26
- # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
27
- # * +root+: a path to the root of the application.
21
+ # * +env+: current environment (like Rails.env).
22
+ # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
23
+ # * +db_dir+: your +db+ directory.
24
+ # * +fixtures_path+: a path to fixtures directory.
25
+ # * +migrations_paths+: a list of paths to directories with migrations.
26
+ # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
27
+ # * +root+: a path to the root of the application.
28
28
  #
29
- # Example usage of +DatabaseTasks+ outside Rails could look as such:
29
+ # Example usage of DatabaseTasks outside Rails could look as such:
30
30
  #
31
31
  # include ActiveRecord::Tasks
32
32
  # DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
@@ -42,6 +42,22 @@ module ActiveRecord
42
42
 
43
43
  LOCAL_HOSTS = ['127.0.0.1', 'localhost']
44
44
 
45
+ def check_protected_environments!
46
+ unless ENV['DISABLE_DATABASE_ENVIRONMENT_CHECK']
47
+ current = ActiveRecord::Migrator.current_environment
48
+ stored = ActiveRecord::Migrator.last_stored_environment
49
+
50
+ if ActiveRecord::Migrator.protected_environment?
51
+ raise ActiveRecord::ProtectedEnvironmentError.new(stored)
52
+ end
53
+
54
+ if stored && stored != current
55
+ raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
56
+ end
57
+ end
58
+ rescue ActiveRecord::NoDatabaseError
59
+ end
60
+
45
61
  def register_task(pattern, task)
46
62
  @tasks ||= {}
47
63
  @tasks[pattern] = task
@@ -91,15 +107,21 @@ module ActiveRecord
91
107
  def create(*arguments)
92
108
  configuration = arguments.first
93
109
  class_for_adapter(configuration['adapter']).new(*arguments).create
110
+ $stdout.puts "Created database '#{configuration['database']}'"
94
111
  rescue DatabaseAlreadyExists
95
- $stderr.puts "#{configuration['database']} already exists"
112
+ $stderr.puts "Database '#{configuration['database']}' already exists"
96
113
  rescue Exception => error
97
- $stderr.puts error, *(error.backtrace)
114
+ $stderr.puts error
98
115
  $stderr.puts "Couldn't create database for #{configuration.inspect}"
116
+ raise
99
117
  end
100
118
 
101
119
  def create_all
120
+ old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
102
121
  each_local_configuration { |configuration| create configuration }
122
+ if old_pool
123
+ ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec)
124
+ end
103
125
  end
104
126
 
105
127
  def create_current(environment = env)
@@ -112,11 +134,13 @@ module ActiveRecord
112
134
  def drop(*arguments)
113
135
  configuration = arguments.first
114
136
  class_for_adapter(configuration['adapter']).new(*arguments).drop
137
+ $stdout.puts "Dropped database '#{configuration['database']}'"
115
138
  rescue ActiveRecord::NoDatabaseError
116
139
  $stderr.puts "Database '#{configuration['database']}' does not exist"
117
140
  rescue Exception => error
118
- $stderr.puts error, *(error.backtrace)
119
- $stderr.puts "Couldn't drop #{configuration['database']}"
141
+ $stderr.puts error
142
+ $stderr.puts "Couldn't drop database '#{configuration['database']}'"
143
+ raise
120
144
  end
121
145
 
122
146
  def drop_all
@@ -134,9 +158,10 @@ module ActiveRecord
134
158
  version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
135
159
  scope = ENV['SCOPE']
136
160
  verbose_was, Migration.verbose = Migration.verbose, verbose
137
- Migrator.migrate(Migrator.migrations_paths, version) do |migration|
161
+ Migrator.migrate(migrations_paths, version) do |migration|
138
162
  scope.blank? || scope == migration.scope
139
163
  end
164
+ ActiveRecord::Base.clear_cache!
140
165
  ensure
141
166
  Migration.verbose = verbose_was
142
167
  end
@@ -188,27 +213,7 @@ module ActiveRecord
188
213
  class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
189
214
  end
190
215
 
191
- def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
192
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
193
- This method will act on a specific connection in the future.
194
- To act on the current connection, use `load_schema_current` instead.
195
- MSG
196
-
197
- load_schema_current(format, file)
198
- end
199
-
200
- def schema_file(format = ActiveSupport::Base.schema_format)
201
- case format
202
- when :ruby
203
- File.join(db_dir, "schema.rb")
204
- when :sql
205
- File.join(db_dir, "structure.sql")
206
- end
207
- end
208
-
209
- # This method is the successor of +load_schema+. We should rename it
210
- # after +load_schema+ went through a deprecation cycle. (Rails > 4.2)
211
- def load_schema_for(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
216
+ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
212
217
  file ||= schema_file(format)
213
218
 
214
219
  case format
@@ -222,24 +227,37 @@ module ActiveRecord
222
227
  else
223
228
  raise ArgumentError, "unknown format #{format.inspect}"
224
229
  end
230
+ ActiveRecord::InternalMetadata.create_table
231
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
225
232
  end
226
233
 
227
- def load_schema_current_if_exists(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
228
- if File.exist?(file || schema_file(format))
229
- load_schema_current(format, file, environment)
234
+ def load_schema_for(*args)
235
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
236
+ This method was renamed to `#load_schema` and will be removed in the future.
237
+ Use `#load_schema` instead.
238
+ MSG
239
+ load_schema(*args)
240
+ end
241
+
242
+ def schema_file(format = ActiveRecord::Base.schema_format)
243
+ case format
244
+ when :ruby
245
+ File.join(db_dir, "schema.rb")
246
+ when :sql
247
+ File.join(db_dir, "structure.sql")
230
248
  end
231
249
  end
232
250
 
233
251
  def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
234
252
  each_current_configuration(environment) { |configuration|
235
- load_schema_for configuration, format, file
253
+ load_schema configuration, format, file
236
254
  }
237
255
  ActiveRecord::Base.establish_connection(environment.to_sym)
238
256
  end
239
257
 
240
258
  def check_schema_file(filename)
241
259
  unless File.exist?(filename)
242
- message = %{#{filename} doesn't exist yet. Run `rake db:migrate` to create it, then try again.}
260
+ message = %{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}
243
261
  message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails)
244
262
  Kernel.abort message
245
263
  end
@@ -267,8 +285,7 @@ module ActiveRecord
267
285
 
268
286
  def each_current_configuration(environment)
269
287
  environments = [environment]
270
- # add test environment only if no RAILS_ENV was specified.
271
- environments << 'test' if environment == 'development' && ENV['RAILS_ENV'].nil?
288
+ environments << 'test' if environment == 'development'
272
289
 
273
290
  configurations = ActiveRecord::Base.configurations.values_at(*environments)
274
291
  configurations.compact.each do |configuration|
@@ -1,8 +1,6 @@
1
1
  module ActiveRecord
2
2
  module Tasks # :nodoc:
3
3
  class MySQLDatabaseTasks # :nodoc:
4
- DEFAULT_CHARSET = ENV['CHARSET'] || 'utf8'
5
- DEFAULT_COLLATION = ENV['COLLATION'] || 'utf8_unicode_ci'
6
4
  ACCESS_DENIED_ERROR = 1045
7
5
 
8
6
  delegate :connection, :establish_connection, to: ActiveRecord::Base
@@ -23,7 +21,7 @@ module ActiveRecord
23
21
  end
24
22
  rescue error_class => error
25
23
  if error.respond_to?(:errno) && error.errno == ACCESS_DENIED_ERROR
26
- $stdout.print error.error
24
+ $stdout.print error.message
27
25
  establish_connection root_configuration_without_database
28
26
  connection.create_database configuration['database'], creation_options
29
27
  if configuration['username'] != 'root'
@@ -56,21 +54,21 @@ module ActiveRecord
56
54
  end
57
55
 
58
56
  def structure_dump(filename)
59
- args = prepare_command_options('mysqldump')
57
+ args = prepare_command_options
60
58
  args.concat(["--result-file", "#{filename}"])
61
59
  args.concat(["--no-data"])
60
+ args.concat(["--routines"])
62
61
  args.concat(["#{configuration['database']}"])
63
- unless Kernel.system(*args)
64
- $stderr.puts "Could not dump the database structure. "\
65
- "Make sure `mysqldump` is in your PATH and check the command output for warnings."
66
- end
62
+
63
+ run_cmd('mysqldump', args, 'dumping')
67
64
  end
68
65
 
69
66
  def structure_load(filename)
70
- args = prepare_command_options('mysql')
67
+ args = prepare_command_options
71
68
  args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
72
69
  args.concat(["--database", "#{configuration['database']}"])
73
- Kernel.system(*args)
70
+
71
+ run_cmd('mysql', args, 'loading')
74
72
  end
75
73
 
76
74
  private
@@ -87,12 +85,6 @@ module ActiveRecord
87
85
  Hash.new.tap do |options|
88
86
  options[:charset] = configuration['encoding'] if configuration.include? 'encoding'
89
87
  options[:collation] = configuration['collation'] if configuration.include? 'collation'
90
-
91
- # Set default charset only when collation isn't set.
92
- options[:charset] ||= DEFAULT_CHARSET unless options[:collation]
93
-
94
- # Set default collation only when charset is also default.
95
- options[:collation] ||= DEFAULT_COLLATION if options[:charset] == DEFAULT_CHARSET
96
88
  end
97
89
  end
98
90
 
@@ -102,8 +94,6 @@ module ActiveRecord
102
94
  ArJdbcMySQL::Error
103
95
  elsif defined?(Mysql2)
104
96
  Mysql2::Error
105
- elsif defined?(Mysql)
106
- Mysql::Error
107
97
  else
108
98
  StandardError
109
99
  end
@@ -129,17 +119,33 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
129
119
  $stdin.gets.strip
130
120
  end
131
121
 
132
- def prepare_command_options(command)
133
- args = [command]
134
- args.concat(['--user', configuration['username']]) if configuration['username']
135
- args << "--password=#{configuration['password']}" if configuration['password']
136
- args.concat(['--default-character-set', configuration['encoding']]) if configuration['encoding']
137
- configuration.slice('host', 'port', 'socket').each do |k, v|
138
- args.concat([ "--#{k}", v.to_s ]) if v
139
- end
122
+ def prepare_command_options
123
+ args = {
124
+ 'host' => '--host',
125
+ 'port' => '--port',
126
+ 'socket' => '--socket',
127
+ 'username' => '--user',
128
+ 'password' => '--password',
129
+ 'encoding' => '--default-character-set',
130
+ 'sslca' => '--ssl-ca',
131
+ 'sslcert' => '--ssl-cert',
132
+ 'sslcapath' => '--ssl-capath',
133
+ 'sslcipher' => '--ssl-cipher',
134
+ 'sslkey' => '--ssl-key'
135
+ }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
140
136
 
141
137
  args
142
138
  end
139
+
140
+ def run_cmd(cmd, args, action)
141
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
142
+ end
143
+
144
+ def run_cmd_error(cmd, args, action)
145
+ msg = "failed to execute: `#{cmd}`\n"
146
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
147
+ msg
148
+ end
143
149
  end
144
150
  end
145
151
  end
@@ -1,5 +1,3 @@
1
- require 'shellwords'
2
-
3
1
  module ActiveRecord
4
2
  module Tasks # :nodoc:
5
3
  class PostgreSQLDatabaseTasks # :nodoc:
@@ -46,20 +44,31 @@ module ActiveRecord
46
44
 
47
45
  def structure_dump(filename)
48
46
  set_psql_env
49
- search_path = configuration['schema_search_path']
50
- unless search_path.blank?
51
- search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
52
- end
53
47
 
54
- command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
55
- raise 'Error dumping database' unless Kernel.system(command)
48
+ search_path = case ActiveRecord::Base.dump_schemas
49
+ when :schema_search_path
50
+ configuration['schema_search_path']
51
+ when :all
52
+ nil
53
+ when String
54
+ ActiveRecord::Base.dump_schemas
55
+ end
56
56
 
57
+ args = ['-s', '-x', '-O', '-f', filename]
58
+ unless search_path.blank?
59
+ args += search_path.split(',').map do |part|
60
+ "--schema=#{part.strip}"
61
+ end
62
+ end
63
+ args << configuration['database']
64
+ run_cmd('pg_dump', args, 'dumping')
57
65
  File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
58
66
  end
59
67
 
60
68
  def structure_load(filename)
61
69
  set_psql_env
62
- Kernel.system("psql -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
70
+ args = [ '-q', '-f', filename, configuration['database'] ]
71
+ run_cmd('psql', args, 'loading' )
63
72
  end
64
73
 
65
74
  private
@@ -85,6 +94,17 @@ module ActiveRecord
85
94
  ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
86
95
  ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
87
96
  end
97
+
98
+ def run_cmd(cmd, args, action)
99
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
100
+ end
101
+
102
+ def run_cmd_error(cmd, args, action)
103
+ msg = "failed to execute:\n"
104
+ msg << "#{cmd} #{args.join(' ')}\n\n"
105
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
106
+ msg
107
+ end
88
108
  end
89
109
  end
90
110
  end
@@ -19,11 +19,15 @@ module ActiveRecord
19
19
  path = Pathname.new configuration['database']
20
20
  file = path.absolute? ? path.to_s : File.join(root, path)
21
21
 
22
- FileUtils.rm(file) if File.exist?(file)
22
+ FileUtils.rm(file)
23
+ rescue Errno::ENOENT => error
24
+ raise NoDatabaseError.new(error.message, error)
23
25
  end
24
26
 
25
27
  def purge
26
28
  drop
29
+ rescue NoDatabaseError
30
+ ensure
27
31
  create
28
32
  end
29
33
 
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
- # = Active Record Timestamp
2
+ # = Active Record \Timestamp
3
3
  #
4
4
  # Active Record automatically timestamps create and update operations if the
5
5
  # table has fields named <tt>created_at/created_on</tt> or
@@ -15,14 +15,25 @@ module ActiveRecord
15
15
  #
16
16
  # == Time Zone aware attributes
17
17
  #
18
- # By default, ActiveRecord::Base keeps all the datetime columns time zone aware by executing following code.
18
+ # Active Record keeps all the <tt>datetime</tt> and <tt>time</tt> columns
19
+ # timezone aware. By default, these values are stored in the database as UTC
20
+ # and converted back to the current <tt>Time.zone</tt> when pulled from the database.
19
21
  #
20
- # config.active_record.time_zone_aware_attributes = true
22
+ # This feature can be turned off completely by setting:
21
23
  #
22
- # This feature can easily be turned off by assigning value <tt>false</tt> .
24
+ # config.active_record.time_zone_aware_attributes = false
23
25
  #
24
- # If your attributes are time zone aware and you desire to skip time zone conversion to the current Time.zone
25
- # when reading certain attributes then you can do following:
26
+ # You can also specify that only <tt>datetime</tt> columns should be time-zone
27
+ # aware (while <tt>time</tt> should not) by setting:
28
+ #
29
+ # ActiveRecord::Base.time_zone_aware_types = [:datetime]
30
+ #
31
+ # You can also add database specific timezone aware types. For example, for PostgreSQL:
32
+ #
33
+ # ActiveRecord::Base.time_zone_aware_types += [:tsrange, :tstzrange]
34
+ #
35
+ # Finally, you can indicate specific attributes of a model for which time zone
36
+ # conversion should not applied, for instance by setting:
26
37
  #
27
38
  # class Topic < ActiveRecord::Base
28
39
  # self.skip_time_zone_conversion_for_attributes = [:written_on]
@@ -57,8 +68,8 @@ module ActiveRecord
57
68
  super
58
69
  end
59
70
 
60
- def _update_record(*args)
61
- if should_record_timestamps?
71
+ def _update_record(*args, touch: true, **options)
72
+ if touch && should_record_timestamps?
62
73
  current_time = current_time_from_proper_timezone
63
74
 
64
75
  timestamp_attributes_for_update_in_model.each do |column|
@@ -67,7 +78,7 @@ module ActiveRecord
67
78
  write_attribute(column, current_time)
68
79
  end
69
80
  end
70
- super
81
+ super(*args)
71
82
  end
72
83
 
73
84
  def should_record_timestamps?
@@ -0,0 +1,58 @@
1
+ module ActiveRecord
2
+ # = Active Record Touch Later
3
+ module TouchLater
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_commit_without_transaction_enrollment :touch_deferred_attributes
8
+ end
9
+
10
+ def touch_later(*names) # :nodoc:
11
+ raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
12
+
13
+ @_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
14
+ @_defer_touch_attrs |= names
15
+ @_touch_time = current_time_from_proper_timezone
16
+
17
+ surreptitiously_touch @_defer_touch_attrs
18
+ self.class.connection.add_transaction_record self
19
+
20
+ # touch the parents as we are not calling the after_save callbacks
21
+ self.class.reflect_on_all_associations(:belongs_to).each do |r|
22
+ if touch = r.options[:touch]
23
+ ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, r.foreign_key, r.name, touch, :touch_later)
24
+ end
25
+ end
26
+ end
27
+
28
+ def touch(*names, time: nil) # :nodoc:
29
+ if has_defer_touch_attrs?
30
+ names |= @_defer_touch_attrs
31
+ end
32
+ super(*names, time: time)
33
+ end
34
+
35
+ private
36
+
37
+ def surreptitiously_touch(attrs)
38
+ attrs.each { |attr| write_attribute attr, @_touch_time }
39
+ clear_attribute_changes attrs
40
+ end
41
+
42
+ def touch_deferred_attributes
43
+ if has_defer_touch_attrs? && persisted?
44
+ touch(*@_defer_touch_attrs, time: @_touch_time)
45
+ @_defer_touch_attrs, @_touch_time = nil, nil
46
+ end
47
+ end
48
+
49
+ def has_defer_touch_attrs?
50
+ defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present?
51
+ end
52
+
53
+ def belongs_to_touch_method
54
+ :touch_later
55
+ end
56
+
57
+ end
58
+ end