activerecord 4.2.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 (221) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1372 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +218 -0
  5. data/examples/performance.rb +184 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record.rb +173 -0
  8. data/lib/active_record/aggregations.rb +266 -0
  9. data/lib/active_record/association_relation.rb +22 -0
  10. data/lib/active_record/associations.rb +1724 -0
  11. data/lib/active_record/associations/alias_tracker.rb +87 -0
  12. data/lib/active_record/associations/association.rb +253 -0
  13. data/lib/active_record/associations/association_scope.rb +194 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +111 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
  16. data/lib/active_record/associations/builder/association.rb +149 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +116 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +91 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +124 -0
  20. data/lib/active_record/associations/builder/has_many.rb +15 -0
  21. data/lib/active_record/associations/builder/has_one.rb +23 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +38 -0
  23. data/lib/active_record/associations/collection_association.rb +634 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1027 -0
  25. data/lib/active_record/associations/has_many_association.rb +184 -0
  26. data/lib/active_record/associations/has_many_through_association.rb +238 -0
  27. data/lib/active_record/associations/has_one_association.rb +105 -0
  28. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  29. data/lib/active_record/associations/join_dependency.rb +282 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +122 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +22 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  33. data/lib/active_record/associations/preloader.rb +203 -0
  34. data/lib/active_record/associations/preloader/association.rb +162 -0
  35. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  36. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  37. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  38. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  39. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  40. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  41. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  42. data/lib/active_record/associations/preloader/through_association.rb +96 -0
  43. data/lib/active_record/associations/singular_association.rb +86 -0
  44. data/lib/active_record/associations/through_association.rb +96 -0
  45. data/lib/active_record/attribute.rb +149 -0
  46. data/lib/active_record/attribute_assignment.rb +212 -0
  47. data/lib/active_record/attribute_decorators.rb +66 -0
  48. data/lib/active_record/attribute_methods.rb +439 -0
  49. data/lib/active_record/attribute_methods/before_type_cast.rb +71 -0
  50. data/lib/active_record/attribute_methods/dirty.rb +181 -0
  51. data/lib/active_record/attribute_methods/primary_key.rb +128 -0
  52. data/lib/active_record/attribute_methods/query.rb +40 -0
  53. data/lib/active_record/attribute_methods/read.rb +103 -0
  54. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  55. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
  56. data/lib/active_record/attribute_methods/write.rb +83 -0
  57. data/lib/active_record/attribute_set.rb +77 -0
  58. data/lib/active_record/attribute_set/builder.rb +86 -0
  59. data/lib/active_record/attributes.rb +139 -0
  60. data/lib/active_record/autosave_association.rb +439 -0
  61. data/lib/active_record/base.rb +317 -0
  62. data/lib/active_record/callbacks.rb +313 -0
  63. data/lib/active_record/coders/json.rb +13 -0
  64. data/lib/active_record/coders/yaml_column.rb +38 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +659 -0
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +373 -0
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +133 -0
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +574 -0
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +991 -0
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +219 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -0
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +883 -0
  78. data/lib/active_record/connection_adapters/column.rb +82 -0
  79. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +282 -0
  81. data/lib/active_record/connection_adapters/mysql_adapter.rb +491 -0
  82. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  111. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  112. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +588 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +754 -0
  117. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +628 -0
  119. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  120. data/lib/active_record/connection_handling.rb +132 -0
  121. data/lib/active_record/core.rb +566 -0
  122. data/lib/active_record/counter_cache.rb +175 -0
  123. data/lib/active_record/dynamic_matchers.rb +140 -0
  124. data/lib/active_record/enum.rb +198 -0
  125. data/lib/active_record/errors.rb +252 -0
  126. data/lib/active_record/explain.rb +38 -0
  127. data/lib/active_record/explain_registry.rb +30 -0
  128. data/lib/active_record/explain_subscriber.rb +29 -0
  129. data/lib/active_record/fixture_set/file.rb +56 -0
  130. data/lib/active_record/fixtures.rb +1007 -0
  131. data/lib/active_record/gem_version.rb +15 -0
  132. data/lib/active_record/inheritance.rb +247 -0
  133. data/lib/active_record/integration.rb +113 -0
  134. data/lib/active_record/locale/en.yml +47 -0
  135. data/lib/active_record/locking/optimistic.rb +204 -0
  136. data/lib/active_record/locking/pessimistic.rb +77 -0
  137. data/lib/active_record/log_subscriber.rb +75 -0
  138. data/lib/active_record/migration.rb +1051 -0
  139. data/lib/active_record/migration/command_recorder.rb +197 -0
  140. data/lib/active_record/migration/join_table.rb +15 -0
  141. data/lib/active_record/model_schema.rb +340 -0
  142. data/lib/active_record/nested_attributes.rb +548 -0
  143. data/lib/active_record/no_touching.rb +52 -0
  144. data/lib/active_record/null_relation.rb +81 -0
  145. data/lib/active_record/persistence.rb +532 -0
  146. data/lib/active_record/query_cache.rb +56 -0
  147. data/lib/active_record/querying.rb +68 -0
  148. data/lib/active_record/railtie.rb +162 -0
  149. data/lib/active_record/railties/console_sandbox.rb +5 -0
  150. data/lib/active_record/railties/controller_runtime.rb +50 -0
  151. data/lib/active_record/railties/databases.rake +391 -0
  152. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  153. data/lib/active_record/readonly_attributes.rb +23 -0
  154. data/lib/active_record/reflection.rb +881 -0
  155. data/lib/active_record/relation.rb +681 -0
  156. data/lib/active_record/relation/batches.rb +138 -0
  157. data/lib/active_record/relation/calculations.rb +403 -0
  158. data/lib/active_record/relation/delegation.rb +140 -0
  159. data/lib/active_record/relation/finder_methods.rb +528 -0
  160. data/lib/active_record/relation/merger.rb +170 -0
  161. data/lib/active_record/relation/predicate_builder.rb +126 -0
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +47 -0
  163. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  164. data/lib/active_record/relation/query_methods.rb +1176 -0
  165. data/lib/active_record/relation/spawn_methods.rb +75 -0
  166. data/lib/active_record/result.rb +131 -0
  167. data/lib/active_record/runtime_registry.rb +22 -0
  168. data/lib/active_record/sanitization.rb +191 -0
  169. data/lib/active_record/schema.rb +64 -0
  170. data/lib/active_record/schema_dumper.rb +251 -0
  171. data/lib/active_record/schema_migration.rb +56 -0
  172. data/lib/active_record/scoping.rb +87 -0
  173. data/lib/active_record/scoping/default.rb +134 -0
  174. data/lib/active_record/scoping/named.rb +164 -0
  175. data/lib/active_record/serialization.rb +22 -0
  176. data/lib/active_record/serializers/xml_serializer.rb +193 -0
  177. data/lib/active_record/statement_cache.rb +111 -0
  178. data/lib/active_record/store.rb +205 -0
  179. data/lib/active_record/tasks/database_tasks.rb +296 -0
  180. data/lib/active_record/tasks/mysql_database_tasks.rb +145 -0
  181. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  182. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  183. data/lib/active_record/timestamp.rb +121 -0
  184. data/lib/active_record/transactions.rb +417 -0
  185. data/lib/active_record/translation.rb +22 -0
  186. data/lib/active_record/type.rb +23 -0
  187. data/lib/active_record/type/big_integer.rb +13 -0
  188. data/lib/active_record/type/binary.rb +50 -0
  189. data/lib/active_record/type/boolean.rb +30 -0
  190. data/lib/active_record/type/date.rb +46 -0
  191. data/lib/active_record/type/date_time.rb +43 -0
  192. data/lib/active_record/type/decimal.rb +40 -0
  193. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  194. data/lib/active_record/type/decorator.rb +14 -0
  195. data/lib/active_record/type/float.rb +19 -0
  196. data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
  197. data/lib/active_record/type/integer.rb +55 -0
  198. data/lib/active_record/type/mutable.rb +16 -0
  199. data/lib/active_record/type/numeric.rb +36 -0
  200. data/lib/active_record/type/serialized.rb +56 -0
  201. data/lib/active_record/type/string.rb +36 -0
  202. data/lib/active_record/type/text.rb +11 -0
  203. data/lib/active_record/type/time.rb +26 -0
  204. data/lib/active_record/type/time_value.rb +38 -0
  205. data/lib/active_record/type/type_map.rb +64 -0
  206. data/lib/active_record/type/unsigned_integer.rb +15 -0
  207. data/lib/active_record/type/value.rb +101 -0
  208. data/lib/active_record/validations.rb +90 -0
  209. data/lib/active_record/validations/associated.rb +51 -0
  210. data/lib/active_record/validations/presence.rb +67 -0
  211. data/lib/active_record/validations/uniqueness.rb +229 -0
  212. data/lib/active_record/version.rb +8 -0
  213. data/lib/rails/generators/active_record.rb +17 -0
  214. data/lib/rails/generators/active_record/migration.rb +18 -0
  215. data/lib/rails/generators/active_record/migration/migration_generator.rb +70 -0
  216. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +22 -0
  217. data/lib/rails/generators/active_record/migration/templates/migration.rb +45 -0
  218. data/lib/rails/generators/active_record/model/model_generator.rb +52 -0
  219. data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
  220. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  221. metadata +309 -0
@@ -0,0 +1,197 @@
1
+ module ActiveRecord
2
+ class Migration
3
+ # <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
4
+ # a migration and knows how to reverse those commands. The CommandRecorder
5
+ # knows how to invert the following commands:
6
+ #
7
+ # * add_column
8
+ # * add_index
9
+ # * add_timestamps
10
+ # * create_table
11
+ # * create_join_table
12
+ # * remove_timestamps
13
+ # * rename_column
14
+ # * rename_index
15
+ # * rename_table
16
+ class CommandRecorder
17
+ include JoinTable
18
+
19
+ attr_accessor :commands, :delegate, :reverting
20
+
21
+ def initialize(delegate = nil)
22
+ @commands = []
23
+ @delegate = delegate
24
+ @reverting = false
25
+ end
26
+
27
+ # While executing the given block, the recorded will be in reverting mode.
28
+ # All commands recorded will end up being recorded reverted
29
+ # and in reverse order.
30
+ # For example:
31
+ #
32
+ # recorder.revert{ recorder.record(:rename_table, [:old, :new]) }
33
+ # # same effect as recorder.record(:rename_table, [:new, :old])
34
+ def revert
35
+ @reverting = !@reverting
36
+ previous = @commands
37
+ @commands = []
38
+ yield
39
+ ensure
40
+ @commands = previous.concat(@commands.reverse)
41
+ @reverting = !@reverting
42
+ end
43
+
44
+ # record +command+. +command+ should be a method name and arguments.
45
+ # For example:
46
+ #
47
+ # recorder.record(:method_name, [:arg1, :arg2])
48
+ def record(*command, &block)
49
+ if @reverting
50
+ @commands << inverse_of(*command, &block)
51
+ else
52
+ @commands << (command << block)
53
+ end
54
+ end
55
+
56
+ # Returns the inverse of the given command. For example:
57
+ #
58
+ # recorder.inverse_of(:rename_table, [:old, :new])
59
+ # # => [:rename_table, [:new, :old]]
60
+ #
61
+ # This method will raise an +IrreversibleMigration+ exception if it cannot
62
+ # invert the +command+.
63
+ def inverse_of(command, args, &block)
64
+ method = :"invert_#{command}"
65
+ raise IrreversibleMigration unless respond_to?(method, true)
66
+ send(method, args, &block)
67
+ end
68
+
69
+ def respond_to?(*args) # :nodoc:
70
+ super || delegate.respond_to?(*args)
71
+ end
72
+
73
+ [:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
74
+ :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
75
+ :change_column_default, :add_reference, :remove_reference, :transaction,
76
+ :drop_join_table, :drop_table, :execute_block, :enable_extension,
77
+ :change_column, :execute, :remove_columns, :change_column_null,
78
+ :add_foreign_key, :remove_foreign_key
79
+ # irreversible methods need to be here too
80
+ ].each do |method|
81
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
82
+ def #{method}(*args, &block) # def create_table(*args, &block)
83
+ record(:"#{method}", args, &block) # record(:create_table, args, &block)
84
+ end # end
85
+ EOV
86
+ end
87
+ alias :add_belongs_to :add_reference
88
+ alias :remove_belongs_to :remove_reference
89
+
90
+ def change_table(table_name, options = {}) # :nodoc:
91
+ yield delegate.update_table_definition(table_name, self)
92
+ end
93
+
94
+ private
95
+
96
+ module StraightReversions
97
+ private
98
+ { transaction: :transaction,
99
+ execute_block: :execute_block,
100
+ create_table: :drop_table,
101
+ create_join_table: :drop_join_table,
102
+ add_column: :remove_column,
103
+ add_timestamps: :remove_timestamps,
104
+ add_reference: :remove_reference,
105
+ enable_extension: :disable_extension
106
+ }.each do |cmd, inv|
107
+ [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
108
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
109
+ def invert_#{method}(args, &block) # def invert_create_table(args, &block)
110
+ [:#{inverse}, args, block] # [:drop_table, args, block]
111
+ end # end
112
+ EOV
113
+ end
114
+ end
115
+ end
116
+
117
+ include StraightReversions
118
+
119
+ def invert_drop_table(args, &block)
120
+ if args.size == 1 && block == nil
121
+ raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
122
+ end
123
+ super
124
+ end
125
+
126
+ def invert_rename_table(args)
127
+ [:rename_table, args.reverse]
128
+ end
129
+
130
+ def invert_remove_column(args)
131
+ raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2
132
+ super
133
+ end
134
+
135
+ def invert_rename_index(args)
136
+ [:rename_index, [args.first] + args.last(2).reverse]
137
+ end
138
+
139
+ def invert_rename_column(args)
140
+ [:rename_column, [args.first] + args.last(2).reverse]
141
+ end
142
+
143
+ def invert_add_index(args)
144
+ table, columns, options = *args
145
+ options ||= {}
146
+
147
+ index_name = options[:name]
148
+ options_hash = index_name ? { name: index_name } : { column: columns }
149
+
150
+ [:remove_index, [table, options_hash]]
151
+ end
152
+
153
+ def invert_remove_index(args)
154
+ table, options = *args
155
+
156
+ unless options && options.is_a?(Hash) && options[:column]
157
+ raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
158
+ end
159
+
160
+ options = options.dup
161
+ [:add_index, [table, options.delete(:column), options]]
162
+ end
163
+
164
+ alias :invert_add_belongs_to :invert_add_reference
165
+ alias :invert_remove_belongs_to :invert_remove_reference
166
+
167
+ def invert_change_column_null(args)
168
+ args[2] = !args[2]
169
+ [:change_column_null, args]
170
+ end
171
+
172
+ def invert_add_foreign_key(args)
173
+ from_table, to_table, add_options = args
174
+ add_options ||= {}
175
+
176
+ if add_options[:name]
177
+ options = { name: add_options[:name] }
178
+ elsif add_options[:column]
179
+ options = { column: add_options[:column] }
180
+ else
181
+ options = to_table
182
+ end
183
+
184
+ [:remove_foreign_key, [from_table, options]]
185
+ end
186
+
187
+ # Forwards any missing method call to the \target.
188
+ def method_missing(method, *args, &block)
189
+ if @delegate.respond_to?(method)
190
+ @delegate.send(method, *args, &block)
191
+ else
192
+ super
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ class Migration
3
+ module JoinTable #:nodoc:
4
+ private
5
+
6
+ def find_join_table_name(table_1, table_2, options = {})
7
+ options.delete(:table_name) || join_table_name(table_1, table_2)
8
+ end
9
+
10
+ def join_table_name(table_1, table_2)
11
+ ModelSchema.derive_join_table_name(table_1, table_2).to_sym
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,340 @@
1
+ module ActiveRecord
2
+ module ModelSchema
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ ##
7
+ # :singleton-method:
8
+ # Accessor for the prefix type that will be prepended to every primary key column name.
9
+ # The options are :table_name and :table_name_with_underscore. If the first is specified,
10
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
11
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
12
+ # that this is a global setting for all Active Records.
13
+ mattr_accessor :primary_key_prefix_type, instance_writer: false
14
+
15
+ ##
16
+ # :singleton-method:
17
+ # Accessor for the name of the prefix string to prepend to every table name. So if set
18
+ # to "basecamp_", all table names will be named like "basecamp_projects", "basecamp_people",
19
+ # etc. This is a convenient way of creating a namespace for tables in a shared database.
20
+ # By default, the prefix is the empty string.
21
+ #
22
+ # If you are organising your models within modules you can add a prefix to the models within
23
+ # a namespace by defining a singleton method in the parent module called table_name_prefix which
24
+ # returns your chosen prefix.
25
+ class_attribute :table_name_prefix, instance_writer: false
26
+ self.table_name_prefix = ""
27
+
28
+ ##
29
+ # :singleton-method:
30
+ # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
31
+ # "people_basecamp"). By default, the suffix is the empty string.
32
+ #
33
+ # If you are organising your models within modules, you can add a suffix to the models within
34
+ # a namespace by defining a singleton method in the parent module called table_name_suffix which
35
+ # returns your chosen suffix.
36
+ class_attribute :table_name_suffix, instance_writer: false
37
+ self.table_name_suffix = ""
38
+
39
+ ##
40
+ # :singleton-method:
41
+ # Accessor for the name of the schema migrations table. By default, the value is "schema_migrations"
42
+ class_attribute :schema_migrations_table_name, instance_accessor: false
43
+ self.schema_migrations_table_name = "schema_migrations"
44
+
45
+ ##
46
+ # :singleton-method:
47
+ # Indicates whether table names should be the pluralized versions of the corresponding class names.
48
+ # If true, the default table name for a Product class will be +products+. If false, it would just be +product+.
49
+ # See table_name for the full rules on table/class naming. This is true, by default.
50
+ class_attribute :pluralize_table_names, instance_writer: false
51
+ self.pluralize_table_names = true
52
+
53
+ self.inheritance_column = 'type'
54
+
55
+ delegate :type_for_attribute, to: :class
56
+ end
57
+
58
+ # Derives the join table name for +first_table+ and +second_table+. The
59
+ # table names appear in alphabetical order. A common prefix is removed
60
+ # (useful for namespaced models like Music::Artist and Music::Record):
61
+ #
62
+ # artists, records => artists_records
63
+ # records, artists => artists_records
64
+ # music_artists, music_records => music_artists_records
65
+ def self.derive_join_table_name(first_table, second_table) # :nodoc:
66
+ [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
67
+ end
68
+
69
+ module ClassMethods
70
+ # Guesses the table name (in forced lower-case) based on the name of the class in the
71
+ # inheritance hierarchy descending directly from ActiveRecord::Base. So if the hierarchy
72
+ # looks like: Reply < Message < ActiveRecord::Base, then Message is used
73
+ # to guess the table name even when called on Reply. The rules used to do the guess
74
+ # are handled by the Inflector class in Active Support, which knows almost all common
75
+ # English inflections. You can add new inflections in config/initializers/inflections.rb.
76
+ #
77
+ # Nested classes are given table names prefixed by the singular form of
78
+ # the parent's table name. Enclosing modules are not considered.
79
+ #
80
+ # ==== Examples
81
+ #
82
+ # class Invoice < ActiveRecord::Base
83
+ # end
84
+ #
85
+ # file class table_name
86
+ # invoice.rb Invoice invoices
87
+ #
88
+ # class Invoice < ActiveRecord::Base
89
+ # class Lineitem < ActiveRecord::Base
90
+ # end
91
+ # end
92
+ #
93
+ # file class table_name
94
+ # invoice.rb Invoice::Lineitem invoice_lineitems
95
+ #
96
+ # module Invoice
97
+ # class Lineitem < ActiveRecord::Base
98
+ # end
99
+ # end
100
+ #
101
+ # file class table_name
102
+ # invoice/lineitem.rb Invoice::Lineitem lineitems
103
+ #
104
+ # Additionally, the class-level +table_name_prefix+ is prepended and the
105
+ # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix,
106
+ # the table name guess for an Invoice class becomes "myapp_invoices".
107
+ # Invoice::Lineitem becomes "myapp_invoice_lineitems".
108
+ #
109
+ # You can also set your own table name explicitly:
110
+ #
111
+ # class Mouse < ActiveRecord::Base
112
+ # self.table_name = "mice"
113
+ # end
114
+ #
115
+ # Alternatively, you can override the table_name method to define your
116
+ # own computation. (Possibly using <tt>super</tt> to manipulate the default
117
+ # table name.) Example:
118
+ #
119
+ # class Post < ActiveRecord::Base
120
+ # def self.table_name
121
+ # "special_" + super
122
+ # end
123
+ # end
124
+ # Post.table_name # => "special_posts"
125
+ def table_name
126
+ reset_table_name unless defined?(@table_name)
127
+ @table_name
128
+ end
129
+
130
+ # Sets the table name explicitly. Example:
131
+ #
132
+ # class Project < ActiveRecord::Base
133
+ # self.table_name = "project"
134
+ # end
135
+ #
136
+ # You can also just define your own <tt>self.table_name</tt> method; see
137
+ # the documentation for ActiveRecord::Base#table_name.
138
+ def table_name=(value)
139
+ value = value && value.to_s
140
+
141
+ if defined?(@table_name)
142
+ return if value == @table_name
143
+ reset_column_information if connected?
144
+ end
145
+
146
+ @table_name = value
147
+ @quoted_table_name = nil
148
+ @arel_table = nil
149
+ @sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
150
+ @relation = Relation.create(self, arel_table)
151
+ end
152
+
153
+ # Returns a quoted version of the table name, used to construct SQL statements.
154
+ def quoted_table_name
155
+ @quoted_table_name ||= connection.quote_table_name(table_name)
156
+ end
157
+
158
+ # Computes the table name, (re)sets it internally, and returns it.
159
+ def reset_table_name #:nodoc:
160
+ self.table_name = if abstract_class?
161
+ superclass == Base ? nil : superclass.table_name
162
+ elsif superclass.abstract_class?
163
+ superclass.table_name || compute_table_name
164
+ else
165
+ compute_table_name
166
+ end
167
+ end
168
+
169
+ def full_table_name_prefix #:nodoc:
170
+ (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
171
+ end
172
+
173
+ def full_table_name_suffix #:nodoc:
174
+ (parents.detect {|p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
175
+ end
176
+
177
+ # Defines the name of the table column which will store the class name on single-table
178
+ # inheritance situations.
179
+ #
180
+ # The default inheritance column name is +type+, which means it's a
181
+ # reserved word inside Active Record. To be able to use single-table
182
+ # inheritance with another column name, or to use the column +type+ in
183
+ # your own model for something else, you can set +inheritance_column+:
184
+ #
185
+ # self.inheritance_column = 'zoink'
186
+ def inheritance_column
187
+ (@inheritance_column ||= nil) || superclass.inheritance_column
188
+ end
189
+
190
+ # Sets the value of inheritance_column
191
+ def inheritance_column=(value)
192
+ @inheritance_column = value.to_s
193
+ @explicit_inheritance_column = true
194
+ end
195
+
196
+ def sequence_name
197
+ if base_class == self
198
+ @sequence_name ||= reset_sequence_name
199
+ else
200
+ (@sequence_name ||= nil) || base_class.sequence_name
201
+ end
202
+ end
203
+
204
+ def reset_sequence_name #:nodoc:
205
+ @explicit_sequence_name = false
206
+ @sequence_name = connection.default_sequence_name(table_name, primary_key)
207
+ end
208
+
209
+ # Sets the name of the sequence to use when generating ids to the given
210
+ # value, or (if the value is nil or false) to the value returned by the
211
+ # given block. This is required for Oracle and is useful for any
212
+ # database which relies on sequences for primary key generation.
213
+ #
214
+ # If a sequence name is not explicitly set when using Oracle,
215
+ # it will default to the commonly used pattern of: #{table_name}_seq
216
+ #
217
+ # If a sequence name is not explicitly set when using PostgreSQL, it
218
+ # will discover the sequence corresponding to your primary key for you.
219
+ #
220
+ # class Project < ActiveRecord::Base
221
+ # self.sequence_name = "projectseq" # default would have been "project_seq"
222
+ # end
223
+ def sequence_name=(value)
224
+ @sequence_name = value.to_s
225
+ @explicit_sequence_name = true
226
+ end
227
+
228
+ # Indicates whether the table associated with this class exists
229
+ def table_exists?
230
+ connection.schema_cache.table_exists?(table_name)
231
+ end
232
+
233
+ def attributes_builder # :nodoc:
234
+ @attributes_builder ||= AttributeSet::Builder.new(column_types, primary_key)
235
+ end
236
+
237
+ def column_types # :nodoc:
238
+ @column_types ||= columns_hash.transform_values(&:cast_type).tap do |h|
239
+ h.default = Type::Value.new
240
+ end
241
+ end
242
+
243
+ def type_for_attribute(attr_name) # :nodoc:
244
+ column_types[attr_name]
245
+ end
246
+
247
+ # Returns a hash where the keys are column names and the values are
248
+ # default values when instantiating the AR object for this table.
249
+ def column_defaults
250
+ _default_attributes.to_hash
251
+ end
252
+
253
+ def _default_attributes # :nodoc:
254
+ @default_attributes ||= attributes_builder.build_from_database(
255
+ raw_default_values)
256
+ end
257
+
258
+ # Returns an array of column names as strings.
259
+ def column_names
260
+ @column_names ||= columns.map { |column| column.name }
261
+ end
262
+
263
+ # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
264
+ # and columns used for single table inheritance have been removed.
265
+ def content_columns
266
+ @content_columns ||= columns.reject { |c| c.name == primary_key || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
267
+ end
268
+
269
+ # Resets all the cached information about columns, which will cause them
270
+ # to be reloaded on the next request.
271
+ #
272
+ # The most common usage pattern for this method is probably in a migration,
273
+ # when just after creating a table you want to populate it with some default
274
+ # values, eg:
275
+ #
276
+ # class CreateJobLevels < ActiveRecord::Migration
277
+ # def up
278
+ # create_table :job_levels do |t|
279
+ # t.integer :id
280
+ # t.string :name
281
+ #
282
+ # t.timestamps
283
+ # end
284
+ #
285
+ # JobLevel.reset_column_information
286
+ # %w{assistant executive manager director}.each do |type|
287
+ # JobLevel.create(name: type)
288
+ # end
289
+ # end
290
+ #
291
+ # def down
292
+ # drop_table :job_levels
293
+ # end
294
+ # end
295
+ def reset_column_information
296
+ connection.clear_cache!
297
+ undefine_attribute_methods
298
+ connection.schema_cache.clear_table_cache!(table_name) if table_exists?
299
+
300
+ @arel_engine = nil
301
+ @column_names = nil
302
+ @column_types = nil
303
+ @content_columns = nil
304
+ @default_attributes = nil
305
+ @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
306
+ @relation = nil
307
+ end
308
+
309
+ private
310
+
311
+ # Guesses the table name, but does not decorate it with prefix and suffix information.
312
+ def undecorated_table_name(class_name = base_class.name)
313
+ table_name = class_name.to_s.demodulize.underscore
314
+ pluralize_table_names ? table_name.pluralize : table_name
315
+ end
316
+
317
+ # Computes and returns a table name according to default conventions.
318
+ def compute_table_name
319
+ base = base_class
320
+ if self == base
321
+ # Nested classes are prefixed with singular parent table name.
322
+ if parent < Base && !parent.abstract_class?
323
+ contained = parent.table_name
324
+ contained = contained.singularize if parent.pluralize_table_names
325
+ contained += '_'
326
+ end
327
+
328
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
329
+ else
330
+ # STI subclasses always use their superclass' table.
331
+ base.table_name
332
+ end
333
+ end
334
+
335
+ def raw_default_values
336
+ columns_hash.transform_values(&:default)
337
+ end
338
+ end
339
+ end
340
+ end