activerecord 3.2.22.5 → 4.2.11.3

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 (236) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1632 -609
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +37 -41
  5. data/examples/performance.rb +31 -19
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +56 -42
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -36
  10. data/lib/active_record/associations/association.rb +73 -55
  11. data/lib/active_record/associations/association_scope.rb +143 -82
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +125 -31
  15. data/lib/active_record/associations/builder/belongs_to.rb +89 -61
  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 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +23 -17
  21. data/lib/active_record/associations/collection_association.rb +251 -177
  22. data/lib/active_record/associations/collection_proxy.rb +963 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +113 -22
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -39
  26. data/lib/active_record/associations/has_one_association.rb +43 -20
  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 -107
  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 +62 -33
  38. data/lib/active_record/associations/preloader.rb +101 -79
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +30 -16
  41. data/lib/active_record/associations.rb +463 -345
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +142 -151
  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 +137 -57
  47. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +73 -106
  50. data/lib/active_record/attribute_methods/serialization.rb +44 -94
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
  52. data/lib/active_record/attribute_methods/write.rb +57 -44
  53. data/lib/active_record/attribute_methods.rb +301 -141
  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 +246 -217
  58. data/lib/active_record/base.rb +70 -474
  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 +396 -219
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
  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 +261 -169
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
  75. data/lib/active_record/connection_adapters/column.rb +31 -245
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
  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 +430 -999
  114. data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
  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 +157 -105
  119. data/lib/active_record/dynamic_matchers.rb +119 -63
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +94 -36
  122. data/lib/active_record/explain.rb +15 -63
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +9 -5
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +302 -215
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +143 -70
  129. data/lib/active_record/integration.rb +65 -12
  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 +73 -52
  133. data/lib/active_record/locking/pessimistic.rb +5 -5
  134. data/lib/active_record/log_subscriber.rb +24 -21
  135. data/lib/active_record/migration/command_recorder.rb +124 -32
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +511 -213
  138. data/lib/active_record/model_schema.rb +91 -117
  139. data/lib/active_record/nested_attributes.rb +184 -130
  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 +276 -117
  143. data/lib/active_record/query_cache.rb +19 -37
  144. data/lib/active_record/querying.rb +28 -18
  145. data/lib/active_record/railtie.rb +73 -40
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +4 -3
  148. data/lib/active_record/railties/databases.rake +141 -416
  149. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  150. data/lib/active_record/readonly_attributes.rb +1 -4
  151. data/lib/active_record/reflection.rb +513 -154
  152. data/lib/active_record/relation/batches.rb +91 -43
  153. data/lib/active_record/relation/calculations.rb +199 -161
  154. data/lib/active_record/relation/delegation.rb +116 -25
  155. data/lib/active_record/relation/finder_methods.rb +362 -248
  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 -43
  160. data/lib/active_record/relation/query_methods.rb +928 -167
  161. data/lib/active_record/relation/spawn_methods.rb +48 -149
  162. data/lib/active_record/relation.rb +352 -207
  163. data/lib/active_record/result.rb +101 -10
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +56 -59
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +106 -63
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +50 -57
  170. data/lib/active_record/scoping/named.rb +73 -109
  171. data/lib/active_record/scoping.rb +58 -123
  172. data/lib/active_record/serialization.rb +6 -2
  173. data/lib/active_record/serializers/xml_serializer.rb +12 -22
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +168 -15
  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 +23 -16
  181. data/lib/active_record/transactions.rb +125 -79
  182. data/lib/active_record/type/big_integer.rb +13 -0
  183. data/lib/active_record/type/binary.rb +50 -0
  184. data/lib/active_record/type/boolean.rb +31 -0
  185. data/lib/active_record/type/date.rb +50 -0
  186. data/lib/active_record/type/date_time.rb +54 -0
  187. data/lib/active_record/type/decimal.rb +64 -0
  188. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  189. data/lib/active_record/type/decorator.rb +14 -0
  190. data/lib/active_record/type/float.rb +19 -0
  191. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  192. data/lib/active_record/type/integer.rb +59 -0
  193. data/lib/active_record/type/mutable.rb +16 -0
  194. data/lib/active_record/type/numeric.rb +36 -0
  195. data/lib/active_record/type/serialized.rb +62 -0
  196. data/lib/active_record/type/string.rb +40 -0
  197. data/lib/active_record/type/text.rb +11 -0
  198. data/lib/active_record/type/time.rb +26 -0
  199. data/lib/active_record/type/time_value.rb +38 -0
  200. data/lib/active_record/type/type_map.rb +64 -0
  201. data/lib/active_record/type/unsigned_integer.rb +15 -0
  202. data/lib/active_record/type/value.rb +110 -0
  203. data/lib/active_record/type.rb +23 -0
  204. data/lib/active_record/validations/associated.rb +24 -16
  205. data/lib/active_record/validations/presence.rb +67 -0
  206. data/lib/active_record/validations/uniqueness.rb +123 -64
  207. data/lib/active_record/validations.rb +36 -29
  208. data/lib/active_record/version.rb +5 -7
  209. data/lib/active_record.rb +66 -46
  210. data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
  211. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
  212. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  213. data/lib/rails/generators/active_record/migration.rb +11 -8
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
  215. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  216. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  217. data/lib/rails/generators/active_record.rb +3 -11
  218. metadata +101 -45
  219. data/examples/associations.png +0 -0
  220. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  221. data/lib/active_record/associations/join_helper.rb +0 -55
  222. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  223. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  226. data/lib/active_record/dynamic_finder_match.rb +0 -68
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/fixtures/file.rb +0 -65
  229. data/lib/active_record/identity_map.rb +0 -162
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -360
  232. data/lib/active_record/test_case.rb +0 -73
  233. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  234. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  235. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  236. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -17,13 +17,24 @@ module ActiveRecord
17
17
  cattr_accessor :ignore_tables
18
18
  @@ignore_tables = []
19
19
 
20
- def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
21
- new(connection).dump(stream)
22
- stream
20
+ class << self
21
+ def dump(connection=ActiveRecord::Base.connection, stream=STDOUT, config = ActiveRecord::Base)
22
+ new(connection, generate_options(config)).dump(stream)
23
+ stream
24
+ end
25
+
26
+ private
27
+ def generate_options(config)
28
+ {
29
+ table_name_prefix: config.table_name_prefix,
30
+ table_name_suffix: config.table_name_suffix
31
+ }
32
+ end
23
33
  end
24
34
 
25
35
  def dump(stream)
26
36
  header(stream)
37
+ extensions(stream)
27
38
  tables(stream)
28
39
  trailer(stream)
29
40
  stream
@@ -31,14 +42,15 @@ module ActiveRecord
31
42
 
32
43
  private
33
44
 
34
- def initialize(connection)
45
+ def initialize(connection, options = {})
35
46
  @connection = connection
36
47
  @types = @connection.native_database_types
37
48
  @version = Migrator::current_version rescue nil
49
+ @options = options
38
50
  end
39
51
 
40
52
  def header(stream)
41
- define_params = @version ? ":version => #{@version}" : ""
53
+ define_params = @version ? "version: #{@version}" : ""
42
54
 
43
55
  if stream.respond_to?(:external_encoding) && stream.external_encoding
44
56
  stream.puts "# encoding: #{stream.external_encoding.name}"
@@ -55,7 +67,7 @@ module ActiveRecord
55
67
  # from scratch. The latter is a flawed and unsustainable approach (the more migrations
56
68
  # you'll amass, the slower it'll run and the greater likelihood for issues).
57
69
  #
58
- # It's strongly recommended to check this file into your version control system.
70
+ # It's strongly recommended that you check this file into your version control system.
59
71
 
60
72
  ActiveRecord::Schema.define(#{define_params}) do
61
73
 
@@ -66,17 +78,30 @@ HEADER
66
78
  stream.puts "end"
67
79
  end
68
80
 
81
+ def extensions(stream)
82
+ return unless @connection.supports_extensions?
83
+ extensions = @connection.extensions
84
+ if extensions.any?
85
+ stream.puts " # These are extensions that must be enabled in order to support this database"
86
+ extensions.each do |extension|
87
+ stream.puts " enable_extension #{extension.inspect}"
88
+ end
89
+ stream.puts
90
+ end
91
+ end
92
+
69
93
  def tables(stream)
70
- @connection.tables.sort.each do |tbl|
71
- next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
72
- case ignored
73
- when String; remove_prefix_and_suffix(tbl) == ignored
74
- when Regexp; remove_prefix_and_suffix(tbl) =~ ignored
75
- else
76
- raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
77
- 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) unless ignored?(tbl)
78
104
  end
79
- table(tbl, stream)
80
105
  end
81
106
  end
82
107
 
@@ -86,51 +111,41 @@ HEADER
86
111
  tbl = StringIO.new
87
112
 
88
113
  # first dump primary key column
89
- if @connection.respond_to?(:pk_and_sequence_for)
90
- pk, _ = @connection.pk_and_sequence_for(table)
91
- elsif @connection.respond_to?(:primary_key)
92
- pk = @connection.primary_key(table)
93
- end
114
+ pk = @connection.primary_key(table)
94
115
 
95
116
  tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
96
- if columns.detect { |c| c.name == pk }
117
+ pkcol = columns.detect { |c| c.name == pk }
118
+ if pkcol
97
119
  if pk != 'id'
98
- tbl.print %Q(, :primary_key => "#{pk}")
120
+ tbl.print %Q(, primary_key: "#{pk}")
121
+ elsif pkcol.sql_type == 'bigint'
122
+ tbl.print ", id: :bigserial"
123
+ elsif pkcol.sql_type == 'uuid'
124
+ tbl.print ", id: :uuid"
125
+ tbl.print %Q(, default: #{pkcol.default_function.inspect})
99
126
  end
100
127
  else
101
- tbl.print ", :id => false"
128
+ tbl.print ", id: false"
102
129
  end
103
- tbl.print ", :force => true"
130
+ tbl.print ", force: :cascade"
104
131
  tbl.puts " do |t|"
105
132
 
106
133
  # then dump all non-primary key columns
107
134
  column_specs = columns.map do |column|
108
- raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
135
+ raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
109
136
  next if column.name == pk
110
- spec = {}
111
- spec[:name] = column.name.inspect
112
-
113
- # AR has an optimization which handles zero-scale decimals as integers. This
114
- # code ensures that the dumper still dumps the column as a decimal.
115
- spec[:type] = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
116
- 'decimal'
117
- else
118
- column.type.to_s
119
- end
120
- spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
121
- spec[:precision] = column.precision.inspect if column.precision
122
- spec[:scale] = column.scale.inspect if column.scale
123
- spec[:null] = 'false' unless column.null
124
- spec[:default] = default_string(column.default) if column.has_default?
125
- (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
126
- spec
137
+ @connection.column_spec(column, @types)
127
138
  end.compact
128
139
 
129
140
  # find all migration keys used in this table
130
- keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map{ |k| k.keys }.flatten
141
+ keys = @connection.migration_keys
131
142
 
132
143
  # figure out the lengths for each column based on above keys
133
- lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
144
+ lengths = keys.map { |key|
145
+ column_specs.map { |spec|
146
+ spec[key] ? spec[key].length + 2 : 0
147
+ }.max
148
+ }
134
149
 
135
150
  # the string we're going to sprintf our values against, with standardized column widths
136
151
  format_string = lengths.map{ |len| "%-#{len}s" }
@@ -166,34 +181,26 @@ HEADER
166
181
  stream
167
182
  end
168
183
 
169
- def default_string(value)
170
- case value
171
- when BigDecimal
172
- value.to_s
173
- when Date, DateTime, Time
174
- "'" + value.to_s(:db) + "'"
175
- else
176
- value.inspect
177
- end
178
- end
179
-
180
184
  def indexes(table, stream)
181
185
  if (indexes = @connection.indexes(table)).any?
182
186
  add_index_statements = indexes.map do |index|
183
187
  statement_parts = [
184
- ('add_index ' + remove_prefix_and_suffix(index.table).inspect),
188
+ "add_index #{remove_prefix_and_suffix(index.table).inspect}",
185
189
  index.columns.inspect,
186
- (':name => ' + index.name.inspect),
190
+ "name: #{index.name.inspect}",
187
191
  ]
188
- statement_parts << ':unique => true' if index.unique
192
+ statement_parts << 'unique: true' if index.unique
189
193
 
190
194
  index_lengths = (index.lengths || []).compact
191
- statement_parts << (':length => ' + Hash[index.columns.zip(index.lengths)].inspect) unless index_lengths.empty?
195
+ statement_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any?
192
196
 
193
- index_orders = (index.orders || {})
194
- statement_parts << (':order => ' + index.orders.inspect) unless index_orders.empty?
197
+ index_orders = index.orders || {}
198
+ statement_parts << "order: #{index.orders.inspect}" if index_orders.any?
199
+ statement_parts << "where: #{index.where.inspect}" if index.where
200
+ statement_parts << "using: #{index.using.inspect}" if index.using
201
+ statement_parts << "type: #{index.type.inspect}" if index.type
195
202
 
196
- ' ' + statement_parts.join(', ')
203
+ " #{statement_parts.join(', ')}"
197
204
  end
198
205
 
199
206
  stream.puts add_index_statements.sort.join("\n")
@@ -201,8 +208,44 @@ HEADER
201
208
  end
202
209
  end
203
210
 
211
+ def foreign_keys(table, stream)
212
+ if (foreign_keys = @connection.foreign_keys(table)).any?
213
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
214
+ parts = [
215
+ "add_foreign_key #{remove_prefix_and_suffix(foreign_key.from_table).inspect}",
216
+ remove_prefix_and_suffix(foreign_key.to_table).inspect,
217
+ ]
218
+
219
+ if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
220
+ parts << "column: #{foreign_key.column.inspect}"
221
+ end
222
+
223
+ if foreign_key.custom_primary_key?
224
+ parts << "primary_key: #{foreign_key.primary_key.inspect}"
225
+ end
226
+
227
+ if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
228
+ parts << "name: #{foreign_key.name.inspect}"
229
+ end
230
+
231
+ parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
232
+ parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
233
+
234
+ " #{parts.join(', ')}"
235
+ end
236
+
237
+ stream.puts add_foreign_key_statements.sort.join("\n")
238
+ end
239
+ end
240
+
204
241
  def remove_prefix_and_suffix(table)
205
- table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
242
+ table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
243
+ end
244
+
245
+ def ignored?(table_name)
246
+ ['schema_migrations', ignore_tables].flatten.any? do |ignored|
247
+ ignored === remove_prefix_and_suffix(table_name)
248
+ end
206
249
  end
207
250
  end
208
251
  end
@@ -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
@@ -1,43 +1,35 @@
1
- require 'active_support/concern'
2
-
3
1
  module ActiveRecord
4
2
  module Scoping
5
3
  module Default
6
4
  extend ActiveSupport::Concern
7
5
 
8
6
  included do
9
- # Stores the default scope for the class
10
- class_attribute :default_scopes, :instance_writer => false
7
+ # Stores the default scope for the class.
8
+ class_attribute :default_scopes, instance_writer: false, instance_predicate: false
9
+
11
10
  self.default_scopes = []
12
11
  end
13
12
 
14
13
  module ClassMethods
15
- # Returns a scope for the model without the default_scope.
14
+ # Returns a scope for the model without the previously set scopes.
16
15
  #
17
16
  # class Post < ActiveRecord::Base
18
17
  # def self.default_scope
19
- # where :published => true
18
+ # where published: true
20
19
  # end
21
20
  # end
22
21
  #
23
- # Post.all # Fires "SELECT * FROM posts WHERE published = true"
24
- # 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"
25
25
  #
26
26
  # This method also accepts a block. All queries inside the block will
27
- # not use the default_scope:
27
+ # not use the previously set scopes.
28
28
  #
29
29
  # Post.unscoped {
30
30
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
31
31
  # }
32
- #
33
- # It is recommended to use the block form of unscoped because chaining
34
- # unscoped with <tt>scope</tt> does not work. Assuming that
35
- # <tt>published</tt> is a <tt>scope</tt>, the following two statements
36
- # are equal: the default_scope is applied on both.
37
- #
38
- # Post.unscoped.published
39
- # Post.published
40
- def unscoped #:nodoc:
32
+ def unscoped
41
33
  block_given? ? relation.scoping { yield } : relation
42
34
  end
43
35
 
@@ -51,81 +43,83 @@ module ActiveRecord
51
43
  # the model.
52
44
  #
53
45
  # class Article < ActiveRecord::Base
54
- # default_scope where(:published => true)
46
+ # default_scope { where(published: true) }
55
47
  # end
56
48
  #
57
49
  # Article.all # => SELECT * FROM articles WHERE published = true
58
50
  #
59
- # The <tt>default_scope</tt> is also applied while creating/building a record. It is not
60
- # applied while updating a record.
51
+ # The +default_scope+ is also applied while creating/building a record.
52
+ # It is not applied while updating a record.
61
53
  #
62
54
  # Article.new.published # => true
63
55
  # Article.create.published # => true
64
56
  #
65
- # You can also use <tt>default_scope</tt> with a block, in order to have it lazily evaluated:
66
- #
67
- # class Article < ActiveRecord::Base
68
- # default_scope { where(:published_at => Time.now - 1.week) }
69
- # end
70
- #
71
- # (You can also pass any object which responds to <tt>call</tt> to the <tt>default_scope</tt>
72
- # macro, and it will be called when building the default scope.)
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.)
73
60
  #
74
- # If you use multiple <tt>default_scope</tt> declarations in your model then they will
75
- # be merged together:
61
+ # If you use multiple +default_scope+ declarations in your model then
62
+ # they will be merged together:
76
63
  #
77
64
  # class Article < ActiveRecord::Base
78
- # default_scope where(:published => true)
79
- # default_scope where(:rating => 'G')
65
+ # default_scope { where(published: true) }
66
+ # default_scope { where(rating: 'G') }
80
67
  # end
81
68
  #
82
69
  # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
83
70
  #
84
- # This is also the case with inheritance and module includes where the parent or module
85
- # defines a <tt>default_scope</tt> and the child or including class defines a second one.
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.
86
74
  #
87
- # If you need to do more complex things with a default scope, you can alternatively
88
- # define it as a class method:
75
+ # If you need to do more complex things with a default scope, you can
76
+ # alternatively define it as a class method:
89
77
  #
90
78
  # class Article < ActiveRecord::Base
91
79
  # def self.default_scope
92
80
  # # Should return a scope, you can call 'super' here etc.
93
81
  # end
94
82
  # end
95
- def default_scope(scope = {})
83
+ def default_scope(scope = nil)
96
84
  scope = Proc.new if block_given?
97
- self.default_scopes = default_scopes + [scope]
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]
98
95
  end
99
96
 
100
- def build_default_scope #:nodoc:
101
- if method(:default_scope).owner != ActiveRecord::Scoping::Default::ClassMethods
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
102
101
  evaluate_default_scope { default_scope }
103
102
  elsif default_scopes.any?
104
103
  evaluate_default_scope do
105
- default_scopes.inject(relation) do |default_scope, scope|
106
- if scope.is_a?(Hash)
107
- default_scope.apply_finder_options(scope)
108
- elsif !scope.is_a?(Relation) && scope.respond_to?(:call)
109
- default_scope.merge(scope.call)
110
- else
111
- default_scope.merge(scope)
112
- end
104
+ default_scopes.inject(base_rel) do |default_scope, scope|
105
+ default_scope.merge(base_rel.scoping { scope.call })
113
106
  end
114
107
  end
115
108
  end
116
109
  end
117
110
 
118
- def ignore_default_scope? #:nodoc:
119
- Thread.current["#{self}_ignore_default_scope"]
111
+ def ignore_default_scope? # :nodoc:
112
+ ScopeRegistry.value_for(:ignore_default_scope, self)
120
113
  end
121
114
 
122
- def ignore_default_scope=(ignore) #:nodoc:
123
- Thread.current["#{self}_ignore_default_scope"] = ignore
115
+ def ignore_default_scope=(ignore) # :nodoc:
116
+ ScopeRegistry.set_value_for(:ignore_default_scope, self, ignore)
124
117
  end
125
118
 
126
- # The ignore_default_scope flag is used to prevent an infinite recursion situation where
127
- # a default scope references a scope which has a default scope which references a scope...
128
- def evaluate_default_scope
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:
129
123
  return if ignore_default_scope?
130
124
 
131
125
  begin
@@ -135,7 +129,6 @@ module ActiveRecord
135
129
  self.ignore_default_scope = false
136
130
  end
137
131
  end
138
-
139
132
  end
140
133
  end
141
134
  end