diff options
Diffstat (limited to 'activerecord')
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 |