diff options
Diffstat (limited to 'activerecord')
18 files changed, 143 insertions, 59 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index cf697d8b16..062c548f20 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,16 +1,16 @@ ## Rails 4.0.0 (unreleased) ## * Added Statement Cache to allow the caching of a single statement. The cache works by - duping the relation returned from yielding a statement which allows skipping the AST - building phase. + duping the relation returned from yielding a statement, which allows skipping the AST + building phase for following executes. The cache returns results in array format. Example: - cache = ActiveRecord::StatementCache.new do - Book.where(:name => "my book").limit(100) - end + cache = ActiveRecord::StatementCache.new do + Book.where(name: "my book").limit(100) + end - books = cache.execute + books = cache.execute The solution attempts to get closer to the speed of `find_by_sql` but still maintaining the expressiveness of the Active Record queries. @@ -44,7 +44,6 @@ Ths solution is to build JoinAssociation when two relations with join information are being merged. And later while building the arel use the previously built `JoinAssociation` record in `JoinDependency#graft` to build the right from clause. - Fixes #3002. *Jared Armstrong and Neeraj Singh* @@ -76,7 +75,8 @@ *Michal Cichra* * `has_many` using `:through` now obeys the order clause mentioned in - through association. Fixes #10016. + through association. + Fixes #10016. *Neeraj Singh* @@ -141,7 +141,8 @@ *Ken Mazaika* * Add an `add_index` override in PostgreSQL adapter and MySQL adapter - to allow custom index type support. Fixes #6101. + to allow custom index type support. + Fixes #6101. add_index(:wikis, :body, :using => 'gin') @@ -165,7 +166,6 @@ in the association for a particular id. Then, it will go to the DB if it is not found. This is accomplished by calling `find_by_scan` in collection associations whenever `options[:inverse_of]` is not nil. - Fixes #9470. *John Wang* @@ -1275,7 +1275,7 @@ * Explain only normal CRUD sql (select / update / insert / delete). Fix problem that explains unexplainable sql. - Closes #7544 #6458. + Fixes #7544 #6458. *kennyj* diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 3c92e379f1..5e5995f566 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1073,6 +1073,9 @@ module ActiveRecord # with +attributes+, linked to this object through a foreign key, and that has already # been saved (if it passed the validation). *Note*: This only works if the base model # already exists in the DB, not if it is a new (unsaved) record! + # [collection.create!(attributes = {})] + # Does the same as <tt>collection.create</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt> + # if the record is invalid. # # (*Note*: +collection+ is replaced with the symbol passed as the first argument, so # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.) @@ -1094,6 +1097,7 @@ module ActiveRecord # * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>) # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>) # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>) + # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>) # The declaration can also include an options hash to specialize the behavior of the association. # # === Options diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 729ef8c55a..db0553ea76 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -30,7 +30,7 @@ module ActiveRecord reset_scope end - # Returns the name of the table of the related class: + # Returns the name of the table of the associated class: # # post.comments.aliased_table_name # => "comments" # diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 8a5b312862..56e57cc36e 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -92,7 +92,7 @@ module ActiveRecord # # => ActiveModel::MissingAttributeError: missing attribute: person_id # # *Second:* You can pass a block so it can be used just like Array#select. - # This build an array of objects from the database for the scope, + # This builds an array of objects from the database for the scope, # converting them into an array and iterating through them using # Array#select. # @@ -304,7 +304,7 @@ module ActiveRecord @association.concat(*records) end - # Replace this collection with +other_array+. This will perform a diff + # Replaces this collection with +other_array+. This will perform a diff # and delete/add only records that have changed. # # class Person < ActiveRecord::Base diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb index 9e33ccb59f..b534569063 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb @@ -1,7 +1,7 @@ module ActiveRecord module Associations class JoinDependency # :nodoc: - # A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited + # A JoinPart represents a part of a JoinDependency. It is inherited # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which # everything else is being joined onto. A JoinAssociation represents an association which # is joining to the base. A JoinAssociation may result in more than one actual join diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 25d62fdb85..7f1ebab4cd 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -11,6 +11,12 @@ module ActiveRecord end module ClassMethods + ## + # :method: serialized_attributes + # + # Returns a hash of all the attributes that have been specified for + # serialization as keys and their class restriction as values. + # If you have an attribute that needs to be saved to the database as an # object, and retrieved as the same object, then specify the name of that # attribute using this method and it will be handled automatically. The @@ -44,6 +50,7 @@ module ActiveRecord end end + # *DEPRECATED*: Use ActiveRecord::AttributeMethods::Serialization::ClassMethods#serialized_attributes class level method instead. def serialized_attributes message = "Instance level serialized_attributes method is deprecated, please use class level method." ActiveSupport::Deprecation.warn message @@ -86,10 +93,10 @@ module ActiveRecord # This is only added to the model when serialize is called, which # ensures we do not make things slower when serialization is not used. - module Behavior #:nodoc: + module Behavior # :nodoc: extend ActiveSupport::Concern - module ClassMethods + module ClassMethods # :nodoc: def initialize_attributes(attributes, options = {}) serialized = (options.delete(:serialized) { true }) ? :serialized : :unserialized super(attributes, options) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb index 51f377dfd7..14c97dcefc 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb @@ -20,6 +20,7 @@ module ActiveRecord class Bytea < Type def type_cast(value) + return if value.nil? PGconn.unescape_bytea value end end diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb index 3f175988db..a1943dfcb0 100644 --- a/activerecord/lib/active_record/connection_handling.rb +++ b/activerecord/lib/active_record/connection_handling.rb @@ -54,11 +54,11 @@ module ActiveRecord end def connection_id - ActiveRecord::RuntimeRegistry.instance.connection_id + ActiveRecord::RuntimeRegistry.connection_id end def connection_id=(connection_id) - ActiveRecord::RuntimeRegistry.instance.connection_id = connection_id + ActiveRecord::RuntimeRegistry.connection_id = connection_id end # Returns the configuration of the associated connection as a hash: diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 7a8408155a..733d4e1c67 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -80,11 +80,11 @@ module ActiveRecord class_attribute :default_connection_handler, instance_writer: false def self.connection_handler - ActiveRecord::RuntimeRegistry.instance.connection_handler || self.default_connection_handler + ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler end def self.connection_handler=(handler) - ActiveRecord::RuntimeRegistry.instance.connection_handler = handler + ActiveRecord::RuntimeRegistry.connection_handler = handler end self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb index 69371a1dab..61e5c120df 100644 --- a/activerecord/lib/active_record/log_subscriber.rb +++ b/activerecord/lib/active_record/log_subscriber.rb @@ -3,11 +3,11 @@ module ActiveRecord IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"] def self.runtime=(value) - ActiveRecord::RuntimeRegistry.instance.sql_runtime = value + ActiveRecord::RuntimeRegistry.sql_runtime = value end def self.runtime - ActiveRecord::RuntimeRegistry.instance.sql_runtime ||= 0 + ActiveRecord::RuntimeRegistry.sql_runtime ||= 0 end def self.reset_runtime diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index d3edcf3cdb..451104106c 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -466,7 +466,7 @@ module ActiveRecord @connection.respond_to?(:reverting) && @connection.reverting end - class ReversibleBlockHelper < Struct.new(:reverting) + class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc: def up yield unless reverting end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 9403273db0..60eda96f08 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -75,8 +75,13 @@ module ActiveRecord end end - # Abstract base class for AggregateReflection and AssociationReflection. Objects of + # Base class for AggregateReflection and AssociationReflection. Objects of # AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods. + # + # MacroReflection + # AggregateReflection + # AssociationReflection + # ThroughReflection class MacroReflection # Returns the name of the macro. # diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 06a220216a..6ee3711052 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -34,7 +34,6 @@ module ActiveRecord # # User.where.not(name: "Jon", role: "admin") # # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin' - # def not(opts, *rest) where_value = @scope.send(:build_where, opts, rest).map do |rel| case rel @@ -353,7 +352,7 @@ module ActiveRecord spawn.unscope!(*args) end - def unscope!(*args) + def unscope!(*args) # :nodoc: args.flatten! args.each do |scope| diff --git a/activerecord/lib/active_record/runtime_registry.rb b/activerecord/lib/active_record/runtime_registry.rb index 3f0ac68143..17890dd29f 100644 --- a/activerecord/lib/active_record/runtime_registry.rb +++ b/activerecord/lib/active_record/runtime_registry.rb @@ -1,29 +1,14 @@ require 'active_support/per_thread_registry' module ActiveRecord - # This is a registry class for storing local variables in active record. The - # class allows you to access variables that are local to the current thread. - # These thread local variables are stored as attributes in the - # +RuntimeRegistry+ class. - # - # You can access the thread local variables by calling a variable's name on - # the +RuntimeRegistry+ class. For example, if you wanted to obtain the - # connection handler for the current thread, you would invoke: - # - # ActiveRecord::RuntimeRegistry.instance.connection_handler - # - # The +PerThreadRegistry+ module will make a new +RuntimeRegistry+ instance - # and store it in +Thread.current+. Whenever you make a call for an attribute - # on the +RuntimeRegistry+ class, the call will be sent to the instance that - # is stored in +Thread.current+. - # - # Note that you can also make the following call which would provide an - # equivalent result as the previous code: + # This is a thread locals registry for Active Record. For example # # ActiveRecord::RuntimeRegistry.connection_handler # - # However, this is less performant because it makes a call to +method_missing+ - # before it sends the method call to the +instance+. + # returns the connection handler local to the current thread. + # + # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt> + # for further details. class RuntimeRegistry extend ActiveSupport::PerThreadRegistry diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb index 6ab36a23a7..0cf3d59985 100644 --- a/activerecord/lib/active_record/scoping.rb +++ b/activerecord/lib/active_record/scoping.rb @@ -36,7 +36,7 @@ module ActiveRecord # to get the current_scope for the +Board+ model, then you would use the # following code: # - # registry = ActiveRecord::Scoping::ScopeRegistry.instance + # registry = ActiveRecord::Scoping::ScopeRegistry # registry.set_value_for(:current_scope, "Board", some_new_scope) # # Now when you run: @@ -52,10 +52,6 @@ module ActiveRecord class ScopeRegistry # :nodoc: extend ActiveSupport::PerThreadRegistry - class << self - delegate :value_for, :set_value_for, to: :instance - end - VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope] def initialize diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb index 4a8c54414d..dd4ee0c4a0 100644 --- a/activerecord/lib/active_record/statement_cache.rb +++ b/activerecord/lib/active_record/statement_cache.rb @@ -3,15 +3,15 @@ module ActiveRecord # Statement cache is used to cache a single statement in order to avoid creating the AST again. # Initializing the cache is done by passing the statement in the initialization block: # - # cache = ActiveRecord::StatementCache.new do - # Book.where(:name => "my book").limit(100) - # end + # cache = ActiveRecord::StatementCache.new do + # Book.where(name: "my book").limit(100) + # end # # The cached statement is executed by using the +execute+ method: # - # cache.execute + # cache.execute # - # The relation returned by yield is cached, and for each +execute+ call the cached relation gets duped. + # The relation returned by the block is cached, and for each +execute+ call the cached relation gets duped. # Database is queried when +to_a+ is called on the relation. class StatementCache def initialize diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb new file mode 100644 index 0000000000..d7d77f96e2 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -0,0 +1,87 @@ +# encoding: utf-8 + +require "cases/helper" +require 'active_record/base' +require 'active_record/connection_adapters/postgresql_adapter' + +class PostgresqlByteaTest < ActiveRecord::TestCase + class ByteaDataType < ActiveRecord::Base + self.table_name = 'bytea_data_type' + end + + def setup + @connection = ActiveRecord::Base.connection + begin + @connection.transaction do + @connection.create_table('bytea_data_type') do |t| + t.binary 'payload' + end + end + end + @column = ByteaDataType.columns.find { |c| c.name == 'payload' } + assert(@column.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn)) + end + + def teardown + @connection.execute 'drop table if exists bytea_data_type' + end + + def test_column + assert_equal :binary, @column.type + end + + def test_type_cast_binary_converts_the_encoding + assert @column + + data = "\u001F\x8B" + assert_equal('UTF-8', data.encoding.name) + assert_equal('ASCII-8BIT', @column.type_cast(data).encoding.name) + end + + def test_type_cast_binary_value + data = "\u001F\x8B".force_encoding("BINARY") + assert_equal(data, @column.type_cast(data)) + end + + def test_type_case_nil + assert_equal(nil, @column.type_cast(nil)) + end + + def test_read_value + data = "\u001F" + @connection.execute "insert into bytea_data_type (payload) VALUES ('#{data}')" + record = ByteaDataType.first + assert_equal(data, record.payload) + record.delete + end + + def test_read_nil_value + @connection.execute "insert into bytea_data_type (payload) VALUES (null)" + record = ByteaDataType.first + assert_equal(nil, record.payload) + record.delete + end + + def test_write_value + data = "\u001F" + record = ByteaDataType.create(payload: data) + refute record.new_record? + assert_equal(data, record.payload) + end + + def test_write_binary + data = File.read(File.join(File.dirname(__FILE__), '..', '..', '..', 'assets', 'example.log')) + assert(data.size > 1) + record = ByteaDataType.create(payload: data) + refute record.new_record? + assert_equal(data, record.payload) + assert_equal(data, ByteaDataType.where(id: record.id).first.payload) + end + + def test_write_nil + record = ByteaDataType.create(payload: nil) + refute record.new_record? + assert_equal(nil, record.payload) + assert_equal(nil, ByteaDataType.where(id: record.id).first.payload) + end +end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 83fc0b48f9..bd568af06a 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1377,9 +1377,9 @@ class BasicsTest < ActiveRecord::TestCase UnloadablePost.send(:current_scope=, UnloadablePost.all) UnloadablePost.unloadable - assert_not_nil ActiveRecord::Scoping::ScopeRegistry.instance.value_for(:current_scope, "UnloadablePost") + assert_not_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost") ActiveSupport::Dependencies.remove_unloadable_constants! - assert_nil ActiveRecord::Scoping::ScopeRegistry.instance.value_for(:current_scope, "UnloadablePost") + assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost") ensure Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost) end |