activerecord 5.0.0.1 → 5.0.1.rc1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +196 -2
  3. data/README.rdoc +1 -1
  4. data/lib/active_record.rb +1 -1
  5. data/lib/active_record/aggregations.rb +4 -2
  6. data/lib/active_record/association_relation.rb +4 -1
  7. data/lib/active_record/associations.rb +5 -0
  8. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
  9. data/lib/active_record/associations/builder/singular_association.rb +10 -1
  10. data/lib/active_record/associations/collection_association.rb +22 -17
  11. data/lib/active_record/associations/collection_proxy.rb +20 -7
  12. data/lib/active_record/associations/has_many_through_association.rb +4 -0
  13. data/lib/active_record/associations/join_dependency.rb +10 -4
  14. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  15. data/lib/active_record/associations/preloader/association.rb +18 -4
  16. data/lib/active_record/associations/preloader/collection_association.rb +0 -1
  17. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  18. data/lib/active_record/associations/singular_association.rb +8 -2
  19. data/lib/active_record/attribute.rb +3 -3
  20. data/lib/active_record/attribute_methods.rb +3 -7
  21. data/lib/active_record/attribute_methods/primary_key.rb +14 -1
  22. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  23. data/lib/active_record/attribute_set.rb +2 -0
  24. data/lib/active_record/attribute_set/builder.rb +29 -7
  25. data/lib/active_record/attributes.rb +3 -3
  26. data/lib/active_record/autosave_association.rb +15 -11
  27. data/lib/active_record/base.rb +1 -1
  28. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +40 -32
  29. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  30. data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -0
  31. data/lib/active_record/connection_adapters/abstract/quoting.rb +4 -4
  32. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -7
  33. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -33
  34. data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -5
  35. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +42 -45
  36. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  37. data/lib/active_record/connection_adapters/mysql/database_statements.rb +6 -23
  38. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  39. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -5
  40. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
  41. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -1
  42. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  43. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  44. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -1
  45. data/lib/active_record/connection_adapters/postgresql_adapter.rb +6 -2
  46. data/lib/active_record/core.rb +3 -1
  47. data/lib/active_record/enum.rb +6 -5
  48. data/lib/active_record/gem_version.rb +2 -2
  49. data/lib/active_record/integration.rb +13 -10
  50. data/lib/active_record/migration.rb +6 -5
  51. data/lib/active_record/model_schema.rb +134 -47
  52. data/lib/active_record/no_touching.rb +4 -0
  53. data/lib/active_record/persistence.rb +10 -4
  54. data/lib/active_record/query_cache.rb +13 -15
  55. data/lib/active_record/querying.rb +3 -3
  56. data/lib/active_record/railties/controller_runtime.rb +1 -1
  57. data/lib/active_record/reflection.rb +8 -0
  58. data/lib/active_record/relation.rb +7 -4
  59. data/lib/active_record/relation/calculations.rb +11 -11
  60. data/lib/active_record/relation/delegation.rb +1 -1
  61. data/lib/active_record/relation/finder_methods.rb +11 -9
  62. data/lib/active_record/relation/query_methods.rb +3 -3
  63. data/lib/active_record/result.rb +7 -1
  64. data/lib/active_record/sanitization.rb +11 -1
  65. data/lib/active_record/schema_dumper.rb +10 -17
  66. data/lib/active_record/scoping/named.rb +1 -1
  67. data/lib/active_record/statement_cache.rb +2 -2
  68. data/lib/active_record/table_metadata.rb +4 -3
  69. data/lib/active_record/touch_later.rb +6 -1
  70. data/lib/active_record/type/internal/abstract_json.rb +5 -1
  71. data/lib/active_record/validations/uniqueness.rb +3 -4
  72. metadata +9 -10
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  end
21
21
 
22
22
  def unsigned?
23
- /\bunsigned\z/ === sql_type
23
+ /\A(?:enum|set)\b/ !~ sql_type && /\bunsigned\b/ === sql_type
24
24
  end
25
25
 
26
26
  def case_sensitive?
@@ -13,19 +13,6 @@ module ActiveRecord
13
13
  result
14
14
  end
15
15
 
16
- # Returns a record hash with the column names as keys and column values
17
- # as values.
18
- def select_one(arel, name = nil, binds = [])
19
- arel, binds = binds_from_relation(arel, binds)
20
- @connection.query_options.merge!(as: :hash)
21
- select_result(to_sql(arel, binds), name, binds) do |result|
22
- @connection.next_result while @connection.more_results?
23
- result.first
24
- end
25
- ensure
26
- @connection.query_options.merge!(as: :array)
27
- end
28
-
29
16
  # Returns an array of arrays containing the field values.
30
17
  # Order is the same as that returned by +columns+.
31
18
  def select_rows(sql, name = nil, binds = [])
@@ -37,11 +24,9 @@ module ActiveRecord
37
24
 
38
25
  # Executes the SQL statement in the context of this connection.
39
26
  def execute(sql, name = nil)
40
- if @connection
41
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
42
- # made since we established the connection
43
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
44
- end
27
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
28
+ # made since we established the connection
29
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
45
30
 
46
31
  super
47
32
  end
@@ -84,11 +69,9 @@ module ActiveRecord
84
69
  end
85
70
 
86
71
  def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
87
- if @connection
88
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
89
- # made since we established the connection
90
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
91
- end
72
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
73
+ # made since we established the connection
74
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
92
75
 
93
76
  type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
94
77
 
@@ -2,7 +2,7 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MySQL
4
4
  module Quoting # :nodoc:
5
- QUOTED_TRUE, QUOTED_FALSE = '1', '0'
5
+ QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
6
6
 
7
7
  def quote_column_name(name)
8
8
  @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
@@ -90,7 +90,6 @@ module ActiveRecord
90
90
  #++
91
91
 
92
92
  def active?
93
- return false unless @connection
94
93
  @connection.ping
95
94
  end
96
95
 
@@ -105,10 +104,7 @@ module ActiveRecord
105
104
  # Otherwise, this method does nothing.
106
105
  def disconnect!
107
106
  super
108
- unless @connection.nil?
109
- @connection.close
110
- @connection = nil
111
- end
107
+ @connection.close
112
108
  end
113
109
 
114
110
  private
@@ -124,6 +124,8 @@ module ActiveRecord
124
124
  pk = primary_key(table_ref) if table_ref
125
125
  end
126
126
 
127
+ pk = suppress_composite_primary_key(pk)
128
+
127
129
  if pk && use_insert_returning?
128
130
  sql = "#{sql} RETURNING #{quote_column_name(pk)}"
129
131
  end
@@ -164,6 +166,12 @@ module ActiveRecord
164
166
  def exec_rollback_db_transaction
165
167
  execute "ROLLBACK"
166
168
  end
169
+
170
+ private
171
+
172
+ def suppress_composite_primary_key(pk)
173
+ pk unless pk.is_a?(Array)
174
+ end
167
175
  end
168
176
  end
169
177
  end
@@ -33,7 +33,11 @@ module ActiveRecord
33
33
 
34
34
  def serialize(value)
35
35
  if value.is_a?(::Array)
36
- @pg_encoder.encode(type_cast_array(value, :serialize))
36
+ result = @pg_encoder.encode(type_cast_array(value, :serialize))
37
+ if encoding = determine_encoding_of_strings(value)
38
+ result.force_encoding(encoding)
39
+ end
40
+ result
37
41
  else
38
42
  super
39
43
  end
@@ -63,6 +67,13 @@ module ActiveRecord
63
67
  @subtype.public_send(method, value)
64
68
  end
65
69
  end
70
+
71
+ def determine_encoding_of_strings(value)
72
+ case value
73
+ when ::Array then determine_encoding_of_strings(value.first)
74
+ when ::String then value.encoding
75
+ end
76
+ end
66
77
  end
67
78
  end
68
79
  end
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  :bit
8
8
  end
9
9
 
10
- def cast(value)
10
+ def cast_value(value)
11
11
  if ::String === value
12
12
  case value
13
13
  when /^0x/i
@@ -16,7 +16,7 @@ module ActiveRecord
16
16
  value # Bit-string notation
17
17
  end
18
18
  else
19
- value
19
+ value.to_s
20
20
  end
21
21
  end
22
22
 
@@ -24,6 +24,8 @@ module ActiveRecord
24
24
  def serialize(value)
25
25
  if value.is_a?(::Hash)
26
26
  value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
27
+ elsif value.respond_to?(:to_unsafe_h)
28
+ serialize(value.to_unsafe_h)
27
29
  else
28
30
  value
29
31
  end
@@ -238,6 +238,12 @@ module ActiveRecord
238
238
  PostgreSQLColumn.new(*args)
239
239
  end
240
240
 
241
+ def table_options(table_name) # :nodoc:
242
+ if comment = table_comment(table_name)
243
+ { comment: comment }
244
+ end
245
+ end
246
+
241
247
  # Returns a comment stored in database for given table
242
248
  def table_comment(table_name) # :nodoc:
243
249
  name = Utils.extract_schema_qualified_name(table_name.to_s)
@@ -579,7 +585,7 @@ module ActiveRecord
579
585
  end
580
586
 
581
587
  def foreign_keys(table_name)
582
- fk_info = select_all <<-SQL.strip_heredoc
588
+ fk_info = select_all(<<-SQL.strip_heredoc, 'SCHEMA')
583
589
  SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
584
590
  FROM pg_constraint c
585
591
  JOIN pg_class t1 ON c.conrelid = t1.oid
@@ -764,11 +764,15 @@ module ActiveRecord
764
764
  @case_insensitive_cache[column.sql_type] ||= begin
765
765
  sql = <<-end_sql
766
766
  SELECT exists(
767
+ SELECT * FROM pg_proc
768
+ WHERE proname = 'lower'
769
+ AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
770
+ ) OR exists(
767
771
  SELECT * FROM pg_proc
768
772
  INNER JOIN pg_cast
769
- ON casttarget::text::oidvector = proargtypes
773
+ ON ARRAY[casttarget]::oidvector = proargtypes
770
774
  WHERE proname = 'lower'
771
- AND castsource = '#{column.sql_type}'::regtype::oid
775
+ AND castsource = #{quote column.sql_type}::regtype
772
776
  )
773
777
  end_sql
774
778
  execute_and_clear(sql, "SCHEMA", []) do |result|
@@ -310,8 +310,8 @@ module ActiveRecord
310
310
  # # Instantiates a single new object
311
311
  # User.new(first_name: 'Jamie')
312
312
  def initialize(attributes = nil)
313
- @attributes = self.class._default_attributes.deep_dup
314
313
  self.class.define_attribute_methods
314
+ @attributes = self.class._default_attributes.deep_dup
315
315
 
316
316
  init_internals
317
317
  initialize_internals_callback
@@ -346,6 +346,8 @@ module ActiveRecord
346
346
 
347
347
  self.class.define_attribute_methods
348
348
 
349
+ yield self if block_given?
350
+
349
351
  _run_find_callbacks
350
352
  _run_initialize_callbacks
351
353
 
@@ -159,8 +159,9 @@ module ActiveRecord
159
159
  detect_enum_conflict!(name, name)
160
160
  detect_enum_conflict!(name, "#{name}=")
161
161
 
162
- decorate_attribute_type(name, :enum) do |subtype|
163
- EnumType.new(name, enum_values, subtype)
162
+ attr = attribute_alias?(name) ? attribute_alias(name) : name
163
+ decorate_attribute_type(attr, :enum) do |subtype|
164
+ EnumType.new(attr, enum_values, subtype)
164
165
  end
165
166
 
166
167
  _enum_methods_module.module_eval do
@@ -182,15 +183,15 @@ module ActiveRecord
182
183
 
183
184
  # def active?() status == 0 end
184
185
  klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
185
- define_method("#{value_method_name}?") { self[name] == value.to_s }
186
+ define_method("#{value_method_name}?") { self[attr] == value.to_s }
186
187
 
187
188
  # def active!() update! status: :active end
188
189
  klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
189
- define_method("#{value_method_name}!") { update! name => value }
190
+ define_method("#{value_method_name}!") { update!(attr => value) }
190
191
 
191
192
  # scope :active, -> { where status: 0 }
192
193
  klass.send(:detect_enum_conflict!, name, value_method_name, true)
193
- klass.scope value_method_name, -> { where(name => value) }
194
+ klass.scope value_method_name, -> { where(attr => value) }
194
195
  end
195
196
  end
196
197
  defined_enums[name.to_s] = enum_values
@@ -7,8 +7,8 @@ module ActiveRecord
7
7
  module VERSION
8
8
  MAJOR = 5
9
9
  MINOR = 0
10
- TINY = 0
11
- PRE = "1"
10
+ TINY = 1
11
+ PRE = "rc1"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -53,18 +53,21 @@ module ActiveRecord
53
53
  #
54
54
  # Person.find(5).cache_key(:updated_at, :last_reviewed_at)
55
55
  def cache_key(*timestamp_names)
56
- case
57
- when new_record?
56
+ if new_record?
58
57
  "#{model_name.cache_key}/new"
59
- when timestamp_names.any?
60
- timestamp = max_updated_column_timestamp(timestamp_names)
61
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
62
- "#{model_name.cache_key}/#{id}-#{timestamp}"
63
- when timestamp = max_updated_column_timestamp
64
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
65
- "#{model_name.cache_key}/#{id}-#{timestamp}"
66
58
  else
67
- "#{model_name.cache_key}/#{id}"
59
+ timestamp = if timestamp_names.any?
60
+ max_updated_column_timestamp(timestamp_names)
61
+ else
62
+ max_updated_column_timestamp
63
+ end
64
+
65
+ if timestamp
66
+ timestamp = timestamp.utc.to_s(cache_timestamp_format)
67
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
68
+ else
69
+ "#{model_name.cache_key}/#{id}"
70
+ end
68
71
  end
69
72
  end
70
73
 
@@ -1,5 +1,6 @@
1
+ require "set"
2
+ require "zlib"
1
3
  require "active_support/core_ext/module/attribute_accessors"
2
- require 'set'
3
4
 
4
5
  module ActiveRecord
5
6
  class MigrationError < ActiveRecordError#:nodoc:
@@ -126,9 +127,9 @@ module ActiveRecord
126
127
  class PendingMigrationError < MigrationError#:nodoc:
127
128
  def initialize(message = nil)
128
129
  if !message && defined?(Rails.env)
129
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate RAILS_ENV=#{::Rails.env}")
130
+ super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}")
130
131
  elsif !message
131
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate")
132
+ super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
132
133
  else
133
134
  super
134
135
  end
@@ -145,7 +146,7 @@ module ActiveRecord
145
146
 
146
147
  class NoEnvironmentInSchemaError < MigrationError #:nodoc:
147
148
  def initialize
148
- msg = "Environment data not found in the schema. To resolve this issue, run: \n\n\tbin/rails db:environment:set"
149
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
149
150
  if defined?(Rails.env)
150
151
  super("#{msg} RAILS_ENV=#{::Rails.env}")
151
152
  else
@@ -168,7 +169,7 @@ module ActiveRecord
168
169
  msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
169
170
  msg << "You are running in `#{ current }` environment. "
170
171
  msg << "If you are sure you want to continue, first set the environment using:\n\n"
171
- msg << "\tbin/rails db:environment:set"
172
+ msg << " bin/rails db:environment:set"
172
173
  if defined?(Rails.env)
173
174
  super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
174
175
  else
@@ -2,71 +2,150 @@ module ActiveRecord
2
2
  module ModelSchema
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ ##
6
+ # :singleton-method: primary_key_prefix_type
7
+ # :call-seq: primary_key_prefix_type
8
+ #
9
+ # The prefix type that will be prepended to every primary key column name.
10
+ # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified,
11
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
12
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
13
+ # that this is a global setting for all Active Records.
14
+
15
+ ##
16
+ # :singleton-method: primary_key_prefix_type=
17
+ # :call-seq: primary_key_prefix_type=(prefix_type)
18
+ #
19
+ # Sets the prefix type that will be prepended to every primary key column name.
20
+ # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified,
21
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
22
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
23
+ # that this is a global setting for all Active Records.
24
+
25
+ ##
26
+ # :singleton-method: table_name_prefix
27
+ # :call-seq: table_name_prefix
28
+ #
29
+ # The prefix string to prepend to every table name.
30
+
31
+ ##
32
+ # :singleton-method: table_name_prefix=
33
+ # :call-seq: table_name_prefix=(prefix)
34
+ #
35
+ # Sets the prefix string to prepend to every table name. So if set to "basecamp_", all table
36
+ # names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient
37
+ # way of creating a namespace for tables in a shared database. By default, the prefix is the
38
+ # empty string.
39
+ #
40
+ # If you are organising your models within modules you can add a prefix to the models within
41
+ # a namespace by defining a singleton method in the parent module called table_name_prefix which
42
+ # returns your chosen prefix.
43
+
44
+ ##
45
+ # :singleton-method: table_name_suffix
46
+ # :call-seq: table_name_suffix
47
+ #
48
+ # The suffix string to append to every table name.
49
+
50
+ ##
51
+ # :singleton-method: table_name_suffix=
52
+ # :call-seq: table_name_suffix=(suffix)
53
+ #
54
+ # Works like +table_name_prefix=+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
55
+ # "people_basecamp"). By default, the suffix is the empty string.
56
+ #
57
+ # If you are organising your models within modules, you can add a suffix to the models within
58
+ # a namespace by defining a singleton method in the parent module called table_name_suffix which
59
+ # returns your chosen suffix.
60
+
61
+ ##
62
+ # :singleton-method: schema_migrations_table_name
63
+ # :call-seq: schema_migrations_table_name
64
+ #
65
+ # The name of the schema migrations table. By default, the value is <tt>"schema_migrations"</tt>.
66
+
67
+ ##
68
+ # :singleton-method: schema_migrations_table_name=
69
+ # :call-seq: schema_migrations_table_name=(table_name)
70
+ #
71
+ # Sets the name of the schema migrations table.
72
+
73
+ ##
74
+ # :singleton-method: internal_metadata_table_name
75
+ # :call-seq: internal_metadata_table_name
76
+ #
77
+ # The name of the internal metadata table. By default, the value is <tt>"ar_internal_metadata"</tt>.
78
+
79
+ ##
80
+ # :singleton-method: internal_metadata_table_name=
81
+ # :call-seq: internal_metadata_table_name=(table_name)
82
+ #
83
+ # Sets the name of the internal metadata table.
84
+
85
+ ##
86
+ # :singleton-method: protected_environments
87
+ # :call-seq: protected_environments
88
+ #
89
+ # The array of names of environments where destructive actions should be prohibited. By default,
90
+ # the value is <tt>["production"]</tt>.
91
+
92
+ ##
93
+ # :singleton-method: protected_environments=
94
+ # :call-seq: protected_environments=(environments)
95
+ #
96
+ # Sets an array of names of environments where destructive actions should be prohibited.
97
+
98
+ ##
99
+ # :singleton-method: pluralize_table_names
100
+ # :call-seq: pluralize_table_names
101
+ #
102
+ # Indicates whether table names should be the pluralized versions of the corresponding class names.
103
+ # If true, the default table name for a Product class will be "products". If false, it would just be "product".
104
+ # See table_name for the full rules on table/class naming. This is true, by default.
105
+
106
+ ##
107
+ # :singleton-method: pluralize_table_names=
108
+ # :call-seq: pluralize_table_names=(value)
109
+ #
110
+ # Set whether table names should be the pluralized versions of the corresponding class names.
111
+ # If true, the default table name for a Product class will be "products". If false, it would just be "product".
112
+ # See table_name for the full rules on table/class naming. This is true, by default.
113
+
114
+ ##
115
+ # :singleton-method: ignored_columns
116
+ # :call-seq: ignored_columns
117
+ #
118
+ # The list of columns names the model should ignore. Ignored columns won't have attribute
119
+ # accessors defined, and won't be referenced in SQL queries.
120
+
121
+ ##
122
+ # :singleton-method: ignored_columns=
123
+ # :call-seq: ignored_columns=(columns)
124
+ #
125
+ # Sets the columns names the model should ignore. Ignored columns won't have attribute
126
+ # accessors defined, and won't be referenced in SQL queries.
127
+
5
128
  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
129
  mattr_accessor :primary_key_prefix_type, instance_writer: false
14
130
 
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
131
  class_attribute :table_name_prefix, instance_writer: false
26
132
  self.table_name_prefix = ""
27
133
 
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
134
  class_attribute :table_name_suffix, instance_writer: false
37
135
  self.table_name_suffix = ""
38
136
 
39
- ##
40
- # :singleton-method:
41
- # Accessor for the name of the schema migrations table. By default, the value is "schema_migrations"
42
137
  class_attribute :schema_migrations_table_name, instance_accessor: false
43
138
  self.schema_migrations_table_name = "schema_migrations"
44
139
 
45
- ##
46
- # :singleton-method:
47
- # Accessor for the name of the internal metadata table. By default, the value is "ar_internal_metadata"
48
140
  class_attribute :internal_metadata_table_name, instance_accessor: false
49
141
  self.internal_metadata_table_name = "ar_internal_metadata"
50
142
 
51
- ##
52
- # :singleton-method:
53
- # Accessor for an array of names of environments where destructive actions should be prohibited. By default,
54
- # the value is ["production"]
55
143
  class_attribute :protected_environments, instance_accessor: false
56
144
  self.protected_environments = ["production"]
57
145
 
58
- ##
59
- # :singleton-method:
60
- # Indicates whether table names should be the pluralized versions of the corresponding class names.
61
- # If true, the default table name for a Product class will be +products+. If false, it would just be +product+.
62
- # See table_name for the full rules on table/class naming. This is true, by default.
63
146
  class_attribute :pluralize_table_names, instance_writer: false
64
147
  self.pluralize_table_names = true
65
148
 
66
- ##
67
- # :singleton-method:
68
- # Accessor for the list of columns names the model should ignore. Ignored columns won't have attribute
69
- # accessors defined, and won't be referenced in SQL queries.
70
149
  class_attribute :ignored_columns, instance_accessor: false
71
150
  self.ignored_columns = [].freeze
72
151
 
@@ -249,7 +328,11 @@ module ActiveRecord
249
328
  end
250
329
 
251
330
  def attributes_builder # :nodoc:
252
- @attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key)
331
+ @attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key) do |name|
332
+ unless columns_hash.key?(name)
333
+ _default_attributes[name].dup
334
+ end
335
+ end
253
336
  end
254
337
 
255
338
  def columns_hash # :nodoc:
@@ -278,8 +361,12 @@ module ActiveRecord
278
361
  #
279
362
  # +attr_name+ The name of the attribute to retrieve the type for. Must be
280
363
  # a string
281
- def type_for_attribute(attr_name)
282
- attribute_types[attr_name]
364
+ def type_for_attribute(attr_name, &block)
365
+ if block
366
+ attribute_types.fetch(attr_name, &block)
367
+ else
368
+ attribute_types[attr_name]
369
+ end
283
370
  end
284
371
 
285
372
  # Returns a hash where the keys are column names and the values are