aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md18
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb2
-rw-r--r--activerecord/lib/active_record/attributes.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/transaction.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/core.rb12
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb14
-rw-r--r--activerecord/lib/active_record/log_subscriber.rb4
-rw-r--r--activerecord/lib/active_record/relation.rb5
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb4
-rw-r--r--activerecord/lib/active_record/sanitization.rb7
-rw-r--r--activerecord/lib/active_record/secure_token.rb28
-rw-r--r--activerecord/lib/active_record/statement_cache.rb4
-rw-r--r--activerecord/lib/active_record/transactions.rb4
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb5
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/templates/migration.rb3
-rw-r--r--activerecord/lib/rails/generators/active_record/model/templates/model.rb3
-rw-r--r--activerecord/test/cases/adapters/postgresql/quoting_test.rb9
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb4
-rw-r--r--activerecord/test/cases/dirty_test.rb13
-rw-r--r--activerecord/test/cases/locking_test.rb6
-rw-r--r--activerecord/test/cases/log_subscriber_test.rb7
-rw-r--r--activerecord/test/cases/migration/foreign_key_test.rb2
-rw-r--r--activerecord/test/cases/migration_test.rb2
-rw-r--r--activerecord/test/cases/relation/where_test.rb30
-rw-r--r--activerecord/test/cases/secure_token_test.rb14
29 files changed, 144 insertions, 104 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 3c4f06ccf8..8875b7ae25 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,19 @@
+* `nil` as a value for a binary column in a query no longer logs as
+ "<NULL binary data>", and instead logs as just "nil".
+
+ *Sean Griffin*
+
+* `attribute_will_change!` will no longer cause non-persistable attributes to
+ be sent to the database.
+
+ Fixes #18407.
+
+ *Sean Griffin*
+
+* Remove support for the `protected_attributes` gem.
+
+ *Carlos Antonio da Silva*, *Roberto Miranda*
+
* Fix accessing of fixtures having non-string labels like Fixnum.
*Prathamesh Sonpatki*
@@ -274,7 +290,7 @@
This option enables to define the column name of associated object's type for polymorphic associations.
- *Ulisses Almeida, Kassio Borges*
+ *Ulisses Almeida*, *Kassio Borges*
* Remove deprecated behavior allowing nested arrays to be passed as query
values.
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index d5702accaf..ce7f575150 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -134,7 +134,7 @@ module ActiveRecord
# Serialized attributes should always be written in case they've been
# changed in place.
def keys_for_partial_write
- changed
+ changed & persistable_attribute_names
end
def _field_changed?(attr, old_value)
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index aafb990bc1..b263a89d79 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -9,6 +9,8 @@ module ActiveRecord
class_attribute :user_provided_defaults, instance_accessor: false # :internal:
self.user_provided_columns = {}
self.user_provided_defaults = {}
+
+ delegate :persistable_attribute_names, to: :class
end
module ClassMethods # :nodoc:
@@ -96,6 +98,10 @@ module ActiveRecord
@columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
end
+ def persistable_attribute_names # :nodoc:
+ @persistable_attribute_names ||= connection.schema_cache.columns_hash(table_name).keys
+ end
+
def reset_column_information # :nodoc:
super
clear_caches_calculated_from_columns
@@ -130,6 +136,7 @@ module ActiveRecord
@columns_hash = nil
@content_columns = nil
@default_attributes = nil
+ @persistable_attribute_names = nil
end
def raw_default_values
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 59cdd8e98c..6e631ed9f7 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -285,11 +285,11 @@ module ActiveRecord
def insert_fixture(fixture, table_name)
columns = schema_cache.columns_hash(table_name)
- key_list = []
- value_list = fixture.map do |name, value|
- key_list << quote_column_name(name)
- quote(value, columns[name])
+ binds = fixture.map do |name, value|
+ [columns[name], value]
end
+ key_list = fixture.keys.map { |name| quote_column_name(name) }
+ value_list = prepare_binds_for_database(binds).map { |_, value| quote(value) }
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 143d7d9574..7c1a779577 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -10,6 +10,12 @@ module ActiveRecord
return value.quoted_id if value.respond_to?(:quoted_id)
if column
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Passing a column to `quote` has been deprecated. It is only used
+ for type casting, which should be handled elsewhere. See
+ https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
+ for more information.
+ MSG
value = column.cast_type.type_cast_for_database(value)
end
@@ -90,6 +96,16 @@ module ActiveRecord
value.to_s(:db)
end
+ def prepare_binds_for_database(binds) # :nodoc:
+ binds.map do |column, value|
+ if column
+ column_name = column.name
+ value = column.cast_type.type_cast_for_database(value)
+ end
+ [column_name, value]
+ end
+ end
+
private
def types_which_need_no_typecasting
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
index f6ef3b0675..7535e9147a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
@@ -69,11 +69,11 @@ module ActiveRecord
def rollback_records
ite = records.uniq
while record = ite.shift
- record.rolledback! full_rollback?
+ record.rolledback!(force_restore_state: full_rollback?)
end
ensure
ite.each do |i|
- i.rolledback!(full_rollback?, false)
+ i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
end
end
@@ -88,7 +88,7 @@ module ActiveRecord
end
ensure
ite.each do |i|
- i.committed!(false)
+ i.committed!(should_run_callbacks: false)
end
end
@@ -117,8 +117,6 @@ module ActiveRecord
def commit
connection.release_savepoint(savepoint_name)
super
- parent = connection.transaction_manager.current_transaction
- records.each { |r| parent.add_record(r) }
end
def full_rollback?; false; end
@@ -166,7 +164,9 @@ module ActiveRecord
end
def commit_transaction
- @stack.pop.commit
+ transaction = @stack.pop
+ transaction.commit
+ transaction.records.each { |r| current_transaction.add_record(r) }
end
def rollback_transaction
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index e52b666296..c941c9f1eb 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -113,7 +113,8 @@ module ActiveRecord
class BindCollector < Arel::Collectors::Bind
def compile(bvs, conn)
- super(bvs.map { |bv| conn.quote(*bv.reverse) })
+ casted_binds = conn.prepare_binds_for_database(bvs)
+ super(casted_binds.map { |_, value| conn.quote(value) })
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 5b070cae4f..f4f9747359 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -64,7 +64,7 @@ module ActiveRecord
# <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
# * <tt>:variables</tt> - An optional hash of additional parameters that
# will be used in <tt>SET SESSION key = val</tt> calls on the connection.
- # * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT</tt> statements
+ # * <tt>:insert_returning</tt> - An optional boolean to control the use of <tt>RETURNING</tt> for <tt>INSERT</tt> statements
# defaults to true.
#
# Any further options are used as connection parameters to libpq. See
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 5a5139256d..a7aff9f724 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -274,16 +274,14 @@ module ActiveRecord
# ==== Example:
# # Instantiates a single new object
# User.new(first_name: 'Jamie')
- def initialize(attributes = nil, options = {})
+ def initialize(attributes = nil)
@attributes = self.class._default_attributes.dup
self.class.define_attribute_methods
init_internals
initialize_internals_callback
- # +options+ argument is only needed to make protected_attributes gem easier to hook.
- # Remove it when we drop support to this gem.
- init_attributes(attributes, options) if attributes
+ assign_attributes(attributes) if attributes
yield self if block_given?
_run_initialize_callbacks
@@ -557,12 +555,6 @@ module ActiveRecord
def initialize_internals_callback
end
- # This method is needed to make protected_attributes gem easier to hook.
- # Remove it when we drop support to this gem.
- def init_attributes(attributes, options)
- assign_attributes(attributes)
- end
-
def thaw
if frozen?
@attributes = @attributes.dup
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index 9f053453bd..aeb1a4ddc6 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -66,6 +66,15 @@ module ActiveRecord
send(lock_col + '=', previous_lock_value + 1)
end
+ def _create_record(attribute_names = self.attribute_names, *) # :nodoc:
+ if locking_enabled?
+ # We always want to persist the locking version, even if we don't detect
+ # a change from the default, since the database might have no default
+ attribute_names |= [self.class.locking_column]
+ end
+ super
+ end
+
def _update_record(attribute_names = self.attribute_names) #:nodoc:
return super unless locking_enabled?
return 0 if attribute_names.empty?
@@ -185,11 +194,6 @@ module ActiveRecord
super.to_i
end
- def changed?(old_value, *)
- # Ensure we save if the default was `nil`
- super || old_value == 0
- end
-
def init_with(coder)
__setobj__(coder['subtype'])
end
diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb
index eb64d197f0..a5c7279db9 100644
--- a/activerecord/lib/active_record/log_subscriber.rb
+++ b/activerecord/lib/active_record/log_subscriber.rb
@@ -22,10 +22,10 @@ module ActiveRecord
def render_bind(column, value)
if column
- if column.binary?
+ if column.binary? && value
# This specifically deals with the PG adapter that casts bytea columns into a Hash.
value = value[:value] if value.is_a?(Hash)
- value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
+ value = "<#{value.bytesize} bytes of binary data>"
end
[column.name, value]
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index ab3debc03b..dd78814c6a 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -558,8 +558,9 @@ module ActiveRecord
end
arel = relation.arel
- binds = (arel.bind_values + relation.bind_values).dup
- binds.map! { |bv| connection.quote(*bv.reverse) }
+ binds = arel.bind_values + relation.bind_values
+ binds = connection.prepare_binds_for_database(binds)
+ binds.map! { |_, value| connection.quote(value) }
collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
collect.substitute_binds(binds).join
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index f054e17017..d6e6cb4d05 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1154,13 +1154,11 @@ module ActiveRecord
end
end
- # This function is recursive just for better readablity.
- # #where argument doesn't support more than one level nested hash in real world.
def add_relations_to_bind_values(attributes)
if attributes.is_a?(Hash)
attributes.each_value do |value|
if value.is_a?(ActiveRecord::Relation)
- self.bind_values += value.bind_values
+ self.bind_values += value.arel.bind_values + value.bind_values
else
add_relations_to_bind_values(value)
end
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 768a72a947..313e767dcb 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -3,14 +3,11 @@ module ActiveRecord
extend ActiveSupport::Concern
module ClassMethods
- def quote_value(value, column) #:nodoc:
- connection.quote(value, column)
- end
-
# Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
def sanitize(object) #:nodoc:
connection.quote(object)
end
+ alias_method :quote_value, :sanitize
protected
@@ -156,7 +153,7 @@ module ActiveRecord
# TODO: Deprecate this
def quoted_id
- self.class.quote_value(id, column_for_attribute(self.class.primary_key))
+ self.class.quote_value(@attributes[self.class.primary_key].value_for_database)
end
end
end
diff --git a/activerecord/lib/active_record/secure_token.rb b/activerecord/lib/active_record/secure_token.rb
index 23d4292cbb..be3c3bc847 100644
--- a/activerecord/lib/active_record/secure_token.rb
+++ b/activerecord/lib/active_record/secure_token.rb
@@ -13,35 +13,25 @@ module ActiveRecord
#
# user = User.new
# user.save
- # user.token # => "44539a6a59835a4ee9d7b112"
- # user.auth_token # => "e2426a93718d1817a43abbaa"
+ # user.token # => "4kUgL2pdQMSCQtjE"
+ # user.auth_token # => "77TMHrHJFvFDwodq8w7Ev2m7"
# user.regenerate_token # => true
# user.regenerate_auth_token # => true
#
- # SecureRandom is used to generate the 24-character unique token, so collisions are highly unlikely.
- # We'll check to see if the generated token has been used already using #exists?, and retry up to 10
- # times to find another unused token. After that a RuntimeError is raised if the problem persists.
+ # SecureRandom::base58 is used to generate the 24-character unique token, so collisions are highly unlikely.
#
# Note that it's still possible to generate a race condition in the database in the same way that
# validates_presence_of can. You're encouraged to add a unique index in the database to deal with
# this even more unlikely scenario.
def has_secure_token(attribute = :token)
- # Load securerandom only when has_secure_key is used.
- require 'securerandom'
- define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(attribute) }
- before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token(attribute)) }
+ # Load securerandom only when has_secure_token is used.
+ require 'active_support/core_ext/securerandom'
+ define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token }
+ before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token) }
end
- def generate_unique_secure_token(attribute)
- 10.times do |i|
- SecureRandom.hex(12).tap do |token|
- if exists?(attribute => token)
- raise "Couldn't generate a unique token in 10 attempts!" if i == 9
- else
- return token
- end
- end
- end
+ def generate_unique_secure_token
+ SecureRandom.base58(24)
end
end
end
diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb
index 192a19f05d..3047a81ec4 100644
--- a/activerecord/lib/active_record/statement_cache.rb
+++ b/activerecord/lib/active_record/statement_cache.rb
@@ -47,8 +47,8 @@ module ActiveRecord
def sql_for(binds, connection)
val = @values.dup
- binds = binds.dup
- @indexes.each { |i| val[i] = connection.quote(*binds.shift.reverse) }
+ binds = connection.prepare_binds_for_database(binds)
+ @indexes.each { |i| val[i] = connection.quote(binds.shift.last) }
val.join
end
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 9cef50029b..0fd2862b2c 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -300,7 +300,7 @@ module ActiveRecord
#
# Ensure that it is not called if the object was never persisted (failed create),
# but call it after the commit of a destroyed object.
- def committed!(should_run_callbacks = true) #:nodoc:
+ def committed!(should_run_callbacks: true) #:nodoc:
_run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
ensure
force_clear_transaction_record_state
@@ -308,7 +308,7 @@ module ActiveRecord
# Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record
# state should be rolled back to the beginning or just to the last savepoint.
- def rolledback!(force_restore_state = false, should_run_callbacks = true) #:nodoc:
+ def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
_run_rollback_callbacks if should_run_callbacks
ensure
restore_transaction_record_state(force_restore_state)
diff --git a/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb b/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb
index fd94a2d038..5b3e57dcf6 100644
--- a/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb
@@ -4,6 +4,8 @@ class <%= migration_class_name %> < ActiveRecord::Migration
<% attributes.each do |attribute| -%>
<% if attribute.password_digest? -%>
t.string :password_digest<%= attribute.inject_options %>
+<% elsif attribute.token? -%>
+ t.string :<%= attribute.name %><%= attribute.inject_options %>
<% else -%>
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
<% end -%>
@@ -12,6 +14,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration
t.timestamps
<% end -%>
end
+<% attributes.select(&:token?).each do |attribute| -%>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
+<% end -%>
<% attributes_with_index.each do |attribute| -%>
add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
<% end -%>
diff --git a/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb
index ae9c74fd05..23a377db6a 100644
--- a/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb
@@ -4,6 +4,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration
<% attributes.each do |attribute| -%>
<%- if attribute.reference? -%>
add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
+ <%- elsif attribute.token? -%>
+ add_column :<%= table_name %>, :<%= attribute.name %>, :string<%= attribute.inject_options %>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
<%- else -%>
add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
<%- if attribute.has_index? -%>
diff --git a/activerecord/lib/rails/generators/active_record/model/templates/model.rb b/activerecord/lib/rails/generators/active_record/model/templates/model.rb
index 539d969fce..55dc65c8ad 100644
--- a/activerecord/lib/rails/generators/active_record/model/templates/model.rb
+++ b/activerecord/lib/rails/generators/active_record/model/templates/model.rb
@@ -3,6 +3,9 @@ class <%= class_name %> < <%= parent_class_name.classify %>
<% attributes.select(&:reference?).each do |attribute| -%>
belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %><%= ', required: true' if attribute.required? %>
<% end -%>
+<% attributes.select(&:token?).each do |attribute| -%>
+ has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
+<% end -%>
<% if attributes.any?(&:password_digest?) -%>
has_secure_password
<% end -%>
diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
index 9ac0036d66..894cf1ffa2 100644
--- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
@@ -34,13 +34,14 @@ module ActiveRecord
def test_quote_range
range = "1,2]'; SELECT * FROM users; --".."a"
- c = PostgreSQLColumn.new(nil, nil, OID::Range.new(Type::Integer.new, :int8range))
- assert_equal "'[1,0]'", @conn.quote(range, c)
+ type = OID::Range.new(Type::Integer.new, :int8range)
+ assert_equal "'[1,0]'", @conn.quote(type.type_cast_for_database(range))
end
def test_quote_bit_string
- c = PostgreSQLColumn.new(nil, 1, OID::Bit.new)
- assert_equal nil, @conn.quote("'); SELECT * FROM users; /*\n01\n*/--", c)
+ value = "'); SELECT * FROM users; /*\n01\n*/--"
+ type = OID::Bit.new
+ assert_equal nil, @conn.quote(type.type_cast_for_database(value))
end
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index df497e761c..274e358e4a 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -85,9 +85,9 @@ module ActiveRecord
def test_quoting_binary_strings
value = "hello".encode('ascii-8bit')
- column = Column.new(nil, 1, SQLite3String.new)
+ type = SQLite3String.new
- assert_equal "'hello'", @conn.quote(value, column)
+ assert_equal "'hello'", @conn.quote(type.type_cast_for_database(value))
end
end
end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 5b71bd7e67..ae4a8aab2c 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -708,6 +708,19 @@ class DirtyTest < ActiveRecord::TestCase
assert model.first_name_changed?
end
+ test "attribute_will_change! doesn't try to save non-persistable attributes" do
+ klass = Class.new(ActiveRecord::Base) do
+ self.table_name = 'people'
+ attribute :non_persisted_attribute, ActiveRecord::Type::String.new
+ end
+
+ record = klass.new(first_name: "Sean")
+ record.non_persisted_attribute_will_change!
+
+ assert record.non_persisted_attribute_changed?
+ assert record.save
+ end
+
private
def with_partial_writes(klass, on = true)
old = klass.partial_writes?
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index ee43f07dd7..848174df06 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -215,10 +215,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase
def test_lock_with_custom_column_without_default_sets_version_to_zero
t1 = LockWithCustomColumnWithoutDefault.new
assert_equal 0, t1.custom_lock_version
+ assert_nil t1.custom_lock_version_before_type_cast
- t1.save
- t1 = LockWithCustomColumnWithoutDefault.find(t1.id)
+ t1.save!
+ t1.reload
assert_equal 0, t1.custom_lock_version
+ assert [0, "0"].include?(t1.custom_lock_version_before_type_cast)
end
def test_readonly_attributes
diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb
index a578e81844..97c0350911 100644
--- a/activerecord/test/cases/log_subscriber_test.rb
+++ b/activerecord/test/cases/log_subscriber_test.rb
@@ -125,12 +125,5 @@ class LogSubscriberTest < ActiveRecord::TestCase
wait
assert_match(/<16 bytes of binary data>/, @logger.logged(:debug).join)
end
-
- def test_nil_binary_data_is_logged
- binary = Binary.create(data: "")
- binary.update_attributes(data: nil)
- wait
- assert_match(/<NULL binary data>/, @logger.logged(:debug).join)
- end
end
end
diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb
index ad35d690bd..f8b1bf8c9d 100644
--- a/activerecord/test/cases/migration/foreign_key_test.rb
+++ b/activerecord/test/cases/migration/foreign_key_test.rb
@@ -225,7 +225,7 @@ module ActiveRecord
def silence_stream(stream)
old_stream = stream.dup
- stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
+ stream.reopen(IO::NULL)
stream.sync = true
yield
ensure
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 5829ef2100..7c2d3e81d6 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -939,7 +939,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase
def silence_stream(stream)
old_stream = stream.dup
- stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
+ stream.reopen(IO::NULL)
stream.sync = true
yield
ensure
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index d675953da6..b0573579da 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -1,13 +1,15 @@
require "cases/helper"
-require 'models/author'
-require 'models/price_estimate'
-require 'models/treasure'
-require 'models/post'
-require 'models/comment'
-require 'models/edge'
-require 'models/topic'
-require 'models/binary'
-require 'models/vertex'
+require "models/author"
+require "models/binary"
+require "models/cake_designer"
+require "models/chef"
+require "models/comment"
+require "models/edge"
+require "models/post"
+require "models/price_estimate"
+require "models/topic"
+require "models/treasure"
+require "models/vertex"
module ActiveRecord
class WhereTest < ActiveRecord::TestCase
@@ -26,6 +28,16 @@ module ActiveRecord
}
end
+ def test_where_copies_arel_bind_params
+ chef = Chef.create!
+ CakeDesigner.create!(chef: chef)
+
+ cake_designers = CakeDesigner.joins(:chef).where(chefs: { id: chef.id })
+ chefs = Chef.where(employable: cake_designers)
+
+ assert_equal [chef], chefs.to_a
+ end
+
def test_rewhere_on_root
assert_equal posts(:welcome), Post.rewhere(title: 'Welcome to the weblog').first
end
diff --git a/activerecord/test/cases/secure_token_test.rb b/activerecord/test/cases/secure_token_test.rb
index dc12b528dc..3f7455d12d 100644
--- a/activerecord/test/cases/secure_token_test.rb
+++ b/activerecord/test/cases/secure_token_test.rb
@@ -22,18 +22,4 @@ class SecureTokenTest < ActiveRecord::TestCase
assert_not_equal @user.token, old_token
assert_not_equal @user.auth_token, old_auth_token
end
-
- def test_raise_after_ten_unsuccessful_attempts_to_generate_a_unique_token
- User.stubs(:exists?).returns(*Array.new(10, true))
- assert_raises(RuntimeError) do
- @user.save
- end
- end
-
- def test_return_unique_token_after_nine_unsuccessful_attempts
- User.stubs(:exists?).returns(*Array.new(10) { |i| i == 9 ? false : true })
- @user.save
- assert_not_nil @user.token
- assert_not_nil @user.auth_token
- end
end