diff options
Diffstat (limited to 'activerecord/lib')
26 files changed, 194 insertions, 120 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 69b95f814c..a86e43664e 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1,6 +1,9 @@ require 'active_support/core_ext/enumerable' require 'active_support/core_ext/string/conversions' require 'active_support/core_ext/module/remove_method' +require 'active_support/dependencies/autoload' +require 'active_support/concern' +require 'active_record/errors' module ActiveRecord class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc: diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index b989a1e161..99e7383d42 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -223,7 +223,7 @@ module ActiveRecord end # This should be implemented to return the values of the relevant key(s) on the owner, - # so that when state_state is different from the value stored on the last find_target, + # so that when stale_state is different from the value stored on the last find_target, # the target is stale. # # This is only relevant to certain associations, which is why it returns nil by default. diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb index 1b382f7285..fcdfc1e150 100644 --- a/activerecord/lib/active_record/associations/builder/collection_association.rb +++ b/activerecord/lib/active_record/associations/builder/collection_association.rb @@ -1,5 +1,8 @@ +require 'active_record/associations' + module ActiveRecord::Associations::Builder class CollectionAssociation < Association #:nodoc: + CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove] def valid_options diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 7f39d3083e..54215cf88d 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -576,7 +576,9 @@ module ActiveRecord args.shift if args.first.is_a?(Hash) && args.first.empty? collection = fetch_first_or_last_using_find?(args) ? scope : load_target - collection.send(type, *args).tap {|it| set_inverse_instance it } + collection.send(type, *args).tap do |record| + set_inverse_instance record if record.is_a? ActiveRecord::Base + end end end end diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index c1cd3a4ae3..0848e7afb3 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -72,7 +72,7 @@ module ActiveRecord # books. # - a Hash which specifies multiple association names, as well as # association names for the to-be-preloaded association objects. For - # example, specifying <tt>{ :author => :avatar }</tt> will preload a + # example, specifying <tt>{ author: :avatar }</tt> will preload a # book's author, as well as that author's avatar. # # +:associations+ has the same format as the +:include+ option for @@ -80,8 +80,8 @@ module ActiveRecord # # :books # [ :books, :author ] - # { :author => :avatar } - # [ :books, { :author => :avatar } ] + # { author: :avatar } + # [ :books, { author: :avatar } ] def initialize(records, associations, preload_scope = nil) @records = Array.wrap(records).compact.uniq @associations = Array.wrap(associations) diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb index 32f4557c28..10238555f0 100644 --- a/activerecord/lib/active_record/associations/singular_association.rb +++ b/activerecord/lib/active_record/associations/singular_association.rb @@ -12,7 +12,7 @@ module ActiveRecord target end - # Implements the writer method, e.g. foo.items= for Foo.has_many :items + # Implements the writer method, e.g. foo.bar= for Foo.belongs_to :bar def writer(record) replace(record) end diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index b9e014735b..43520142bf 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -28,7 +28,7 @@ module ActiveRecord # methods which create and delete records on the association. # # We only support indirectly modifying through associations which has a belongs_to source. - # This is the "has_many :tags, :through => :taggings" situation, where the join model + # This is the "has_many :tags, through: :taggings" situation, where the join model # typically has a belongs_to on both side. In other words, associations which could also # be represented as has_and_belongs_to_many associations. # diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 101c641877..437fd00948 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -215,10 +215,10 @@ module ActiveRecord # person = Person.create!(name: 'David Heinemeier Hansson ' * 3) # # person.attribute_for_inspect(:name) - # # => '"David Heinemeier Hansson David Heinemeier Hansson D..."' + # # => "\"David Heinemeier Hansson David Heinemeier Hansson D...\"" # # person.attribute_for_inspect(:created_at) - # # => '"2009-01-12 04:48:57"' + # # => "\"2012-10-22 00:15:07\"" def attribute_for_inspect(attr_name) value = read_attribute(attr_name) @@ -234,14 +234,18 @@ module ActiveRecord # Returns +true+ if the specified +attribute+ has been set by the user or by a # database load and is neither +nil+ nor <tt>empty?</tt> (the latter only applies # to objects that respond to <tt>empty?</tt>, most notably Strings). Otherwise, +false+. + # Note that it always returns +true+ with boolean attributes. # - # class Person < ActiveRecord::Base + # class Task < ActiveRecord::Base # end # - # person = Person.new(name: '') - # person.attribute_present?(:name) # => false + # person = Task.new(title: '', is_done: false) + # person.attribute_present?(:title) # => false + # person.attribute_present?(:is_done) # => true # person.name = 'Francesco' - # person.attribute_present?(:name) # => true + # person.is_done = true + # person.attribute_present?(:title) # => true + # person.attribute_present?(:is_done) # => true def attribute_present?(attribute) value = read_attribute(attribute) !value.nil? && !(value.respond_to?(:empty?) && value.empty?) @@ -265,15 +269,16 @@ module ActiveRecord end # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example, - # "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). - # (Alias for the protected <tt>read_attribute</tt> method). It raises an <tt>ActiveModel::MissingAttributeError</tt> - # error if the identified attribute is missing. + # "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). It raises + # <tt>ActiveModel::MissingAttributeError</tt> if the identified attribute is missing. + # + # Alias for the <tt>read_attribute</tt> method. # # class Person < ActiveRecord::Base # belongs_to :organization # end # - # person = Person.new(name: 'Francesco', age: '22' + # person = Person.new(name: 'Francesco', age: '22') # person[:name] # => "Francesco" # person[:age] # => 22 # diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb index d4f529acbf..a23baeaced 100644 --- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb +++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb @@ -1,5 +1,28 @@ module ActiveRecord module AttributeMethods + # = Active Record Attribute Methods Before Type Cast + # + # <tt>ActiveRecord::AttributeMethods::BeforeTypeCast</tt> provides a way to + # read the value of the attributes before typecasting and deserialization. + # + # class Task < ActiveRecord::Base + # end + # + # task = Task.new(id: '1', completed_on: '2012-10-21') + # task.id # => 1 + # task.completed_on # => Sun, 21 Oct 2012 + # + # task.attributes_before_type_cast + # # => {"id"=>"1", "completed_on"=>"2012-10-21", ... } + # task.read_attribute_before_type_cast('id') # => "1" + # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21" + # + # In addition to #read_attribute_before_type_cast and #attributes_before_type_cast, + # it declares a method for all attributes with the <tt>*_before_type_cast</tt> + # suffix. + # + # task.id_before_type_cast # => "1" + # task.completed_on_before_type_cast # => "2012-10-21" module BeforeTypeCast extend ActiveSupport::Concern @@ -7,11 +30,31 @@ module ActiveRecord attribute_method_suffix "_before_type_cast" end + # Returns the value of the attribute identified by +attr_name+ before + # typecasting and deserialization. + # + # class Task < ActiveRecord::Base + # end + # + # task = Task.new(id: '1', completed_on: '2012-10-21') + # task.read_attribute('id') # => 1 + # task.read_attribute_before_type_cast('id') # => '1' + # task.read_attribute('completed_on') # => Sun, 21 Oct 2012 + # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21" def read_attribute_before_type_cast(attr_name) @attributes[attr_name] end # Returns a hash of attributes before typecasting and deserialization. + # + # class Task < ActiveRecord::Base + # end + # + # task = Task.new(title: nil, is_done: true, completed_on: '2012-10-21') + # task.attributes + # # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>Sun, 21 Oct 2012, "created_at"=>nil, "updated_at"=>nil} + # task.attributes_before_type_cast + # # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil} def attributes_before_type_cast @attributes end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index eabbd80f66..a694a292fe 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -8,7 +8,6 @@ require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/class/delegating_attributes' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/string/behavior' require 'active_support/core_ext/kernel/singleton_class' diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 3aabf3b3f2..725bfffef2 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -212,11 +212,10 @@ module ActiveRecord # # before_destroy :log_children # - # def log_children - # children.each do |child| - # # Some child processing + # private + # def log_children + # # Child processing # end - # end # end # # In this case, the problem is that when the +before_destroy+ callback is executed, the children are not available @@ -227,11 +226,10 @@ module ActiveRecord # # before_destroy :log_children, prepend: true # - # def log_children - # children.each do |child| - # # Some child processing + # private + # def log_children + # # Child processing # end - # end # end # # This way, the +before_destroy+ gets executed before the <tt>dependent: destroy</tt> is called, and the data is still available. 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 0d7046a705..4f3eebce7d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -150,7 +150,7 @@ module ActiveRecord # already-automatically-released savepoints: # # Model.connection.transaction do # BEGIN - # Model.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1 + # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1 # Model.connection.create_table(...) # # active_record_1 now automatically released # end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error! diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 0f6b177b62..38960ab873 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -161,21 +161,21 @@ module ActiveRecord # td.column(:granted, :boolean) # # granted BOOLEAN # - # td.column(:picture, :binary, :limit => 2.megabytes) + # td.column(:picture, :binary, limit: 2.megabytes) # # => picture BLOB(2097152) # - # td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) + # td.column(:sales_stage, :string, limit: 20, default: 'new', null: false) # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL # - # td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) + # td.column(:bill_gates_money, :decimal, precision: 15, scale: 2) # # => bill_gates_money DECIMAL(15,2) # - # td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) + # td.column(:sensor_reading, :decimal, precision: 30, scale: 20) # # => sensor_reading DECIMAL(30,20) # # # While <tt>:scale</tt> defaults to zero on most databases, it # # probably wouldn't hurt to include it. - # td.column(:huge_integer, :decimal, :precision => 30) + # td.column(:huge_integer, :decimal, precision: 30) # # => huge_integer DECIMAL(30) # # # Defines a column with a database-specific type. @@ -190,11 +190,11 @@ module ActiveRecord # # What can be written like this with the regular calls to column: # - # create_table "products", :force => true do |t| + # create_table "products", force: true do |t| # t.column "shop_id", :integer # t.column "creator_id", :integer - # t.column "name", :string, :default => "Untitled" - # t.column "value", :string, :default => "Untitled" + # t.column "name", :string, default: "Untitled" + # t.column "value", :string, default: "Untitled" # t.column "created_at", :datetime # t.column "updated_at", :datetime # end @@ -203,7 +203,7 @@ module ActiveRecord # # create_table :products do |t| # t.integer :shop_id, :creator_id - # t.string :name, :value, :default => "Untitled" + # t.string :name, :value, default: "Untitled" # t.timestamps # end # @@ -218,17 +218,17 @@ module ActiveRecord # create_table :taggings do |t| # t.integer :tag_id, :tagger_id, :taggable_id # t.string :tagger_type - # t.string :taggable_type, :default => 'Photo' + # t.string :taggable_type, default: 'Photo' # end - # add_index :taggings, :tag_id, :name => 'index_taggings_on_tag_id' + # add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id' # add_index :taggings, [:tagger_id, :tagger_type] # # Can also be written as follows using references: # # create_table :taggings do |t| - # t.references :tag, :index => { :name => 'index_taggings_on_tag_id' } - # t.references :tagger, :polymorphic => true, :index => true - # t.references :taggable, :polymorphic => { :default => 'Photo' } + # t.references :tag, index: { name: 'index_taggings_on_tag_id' } + # t.references :tagger, polymorphic: true, index: true + # t.references :taggable, polymorphic: { default: 'Photo' } # end def column(name, type, options = {}) name = name.to_s @@ -266,7 +266,7 @@ module ActiveRecord # Adds index options to the indexes hash, keyed by column name # This is primarily used to track indexes that need to be created after the table # - # index(:account_id, :name => 'index_projects_on_account_id') + # index(:account_id, name: 'index_projects_on_account_id') def index(column_name, options = {}) indexes[column_name] = options end @@ -374,9 +374,9 @@ module ActiveRecord # ====== Creating a simple index # t.index(:name) # ====== Creating a unique index - # t.index([:branch_id, :party_id], :unique => true) + # t.index([:branch_id, :party_id], unique: true) # ====== Creating a named index - # t.index([:branch_id, :party_id], :unique => true, :name => 'by_branch_party') + # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party') def index(column_name, options = {}) @base.add_index(@table_name, column_name, options) end @@ -396,7 +396,7 @@ module ActiveRecord # Changes the column's definition according to the new options. # See TableDefinition#column for details of the options you can use. # - # t.change(:name, :string, :limit => 80) + # t.change(:name, :string, limit: 80) # t.change(:description, :text) def change(column_name, type, options = {}) @base.change_column(@table_name, column_name, type, options) @@ -423,11 +423,11 @@ module ActiveRecord # ====== Remove the index_table_name_on_column in the table_name table # t.remove_index :column # ====== Remove the index named index_table_name_on_branch_id in the table_name table - # t.remove_index :column => :branch_id + # t.remove_index column: :branch_id # ====== Remove the index named index_table_name_on_branch_id_and_party_id in the table_name table - # t.remove_index :column => [:branch_id, :party_id] + # t.remove_index column: [:branch_id, :party_id] # ====== Remove the index named by_branch_party in the table_name table - # t.remove_index :name => :by_branch_party + # t.remove_index name: :by_branch_party def remove_index(options = {}) @base.remove_index(@table_name, options) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 86d6266af9..17dd71e898 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -36,10 +36,10 @@ module ActiveRecord # index_exists?(:suppliers, [:company_id, :company_type]) # # # Check a unique index exists - # index_exists?(:suppliers, :company_id, :unique => true) + # index_exists?(:suppliers, :company_id, unique: true) # # # Check an index with a custom name exists - # index_exists?(:suppliers, :company_id, :name => "idx_company_id" + # index_exists?(:suppliers, :company_id, name: "idx_company_id" def index_exists?(table_name, column_name, options = {}) column_names = Array(column_name) index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names) @@ -89,14 +89,14 @@ module ActiveRecord # # table. # # create_table(:suppliers) do |t| - # t.column :name, :string, :limit => 60 + # t.column :name, :string, limit: 60 # # Other fields here # end # # === Block form, with shorthand # # You can also use the column types as method calls, rather than calling the column method. # create_table(:suppliers) do |t| - # t.string :name, :limit => 60 + # t.string :name, limit: 60 # # Other fields here # end # @@ -104,7 +104,7 @@ module ActiveRecord # # Creates a table called 'suppliers' with no columns. # create_table(:suppliers) # # Add a column to 'suppliers'. - # add_column(:suppliers, :name, :string, {:limit => 60}) + # add_column(:suppliers, :name, :string, {limit: 60}) # # The +options+ hash can include the following keys: # [<tt>:id</tt>] @@ -127,15 +127,15 @@ module ActiveRecord # Defaults to false. # # ====== Add a backend specific option to the generated SQL (MySQL) - # create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8') + # create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8') # generates: # CREATE TABLE suppliers ( # id int(11) DEFAULT NULL auto_increment PRIMARY KEY # ) ENGINE=InnoDB DEFAULT CHARSET=utf8 # # ====== Rename the primary key column - # create_table(:objects, :primary_key => 'guid') do |t| - # t.column :name, :string, :limit => 80 + # create_table(:objects, primary_key: 'guid') do |t| + # t.column :name, :string, limit: 80 # end # generates: # CREATE TABLE objects ( @@ -144,7 +144,7 @@ module ActiveRecord # ) # # ====== Do not add a primary key column - # create_table(:categories_suppliers, :id => false) do |t| + # create_table(:categories_suppliers, id: false) do |t| # t.column :category_id, :integer # t.column :supplier_id, :integer # end @@ -193,7 +193,7 @@ module ActiveRecord # Defaults to false. # # ====== Add a backend specific option to the generated SQL (MySQL) - # create_join_table(:assemblies, :parts, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8') + # create_join_table(:assemblies, :parts, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8') # generates: # CREATE TABLE assemblies_parts ( # assembly_id int NOT NULL, @@ -218,7 +218,7 @@ module ActiveRecord # # # change_table() yields a Table instance # change_table(:suppliers) do |t| - # t.column :name, :string, :limit => 60 + # t.column :name, :string, limit: 60 # # Other column alterations here # end # @@ -231,12 +231,12 @@ module ActiveRecord # # ====== Add a column # change_table(:suppliers) do |t| - # t.column :name, :string, :limit => 60 + # t.column :name, :string, limit: 60 # end # # ====== Add 2 integer columns # change_table(:suppliers) do |t| - # t.integer :width, :height, :null => false, :default => 0 + # t.integer :width, :height, null: false, default: 0 # end # # ====== Add created_at/updated_at columns @@ -253,7 +253,7 @@ module ActiveRecord # # ====== Add a polymorphic foreign key column # change_table(:suppliers) do |t| - # t.belongs_to :company, :polymorphic => true + # t.belongs_to :company, polymorphic: true # end # # Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns @@ -318,7 +318,7 @@ module ActiveRecord # Changes the column's definition according to the new options. # See TableDefinition#column for details of the options you can use. # - # change_column(:suppliers, :name, :string, :limit => 80) + # change_column(:suppliers, :name, :string, limit: 80) # change_column(:accounts, :description, :text) def change_column(table_name, column_name, type, options = {}) raise NotImplementedError, "change_column is not implemented" @@ -352,35 +352,35 @@ module ActiveRecord # CREATE INDEX suppliers_name_index ON suppliers(name) # # ====== Creating a unique index - # add_index(:accounts, [:branch_id, :party_id], :unique => true) + # add_index(:accounts, [:branch_id, :party_id], unique: true) # generates # CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id) # # ====== Creating a named index - # add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party') + # add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party') # generates # CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id) # # ====== Creating an index with specific key length - # add_index(:accounts, :name, :name => 'by_name', :length => 10) + # add_index(:accounts, :name, name: 'by_name', length: 10) # generates # CREATE INDEX by_name ON accounts(name(10)) # - # add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15}) + # add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15}) # generates # CREATE INDEX by_name_surname ON accounts(name(10), surname(15)) # # Note: SQLite doesn't support index length # # ====== Creating an index with a sort order (desc or asc, asc is the default) - # add_index(:accounts, [:branch_id, :party_id, :surname], :order => {:branch_id => :desc, :party_id => :asc}) + # add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc}) # generates # CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname) # # Note: mysql doesn't yet support index order (it accepts the syntax but ignores it) # # ====== Creating a partial index - # add_index(:accounts, [:branch_id, :party_id], :unique => true, :where => "active") + # add_index(:accounts, [:branch_id, :party_id], unique: true, where: "active") # generates # CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active # @@ -396,11 +396,11 @@ module ActiveRecord # Remove the index_accounts_on_column in the accounts table. # remove_index :accounts, :column # Remove the index named index_accounts_on_branch_id in the accounts table. - # remove_index :accounts, :column => :branch_id + # remove_index :accounts, column: :branch_id # Remove the index named index_accounts_on_branch_id_and_party_id in the accounts table. - # remove_index :accounts, :column => [:branch_id, :party_id] + # remove_index :accounts, column: [:branch_id, :party_id] # Remove the index named by_branch_party in the accounts table. - # remove_index :accounts, :name => :by_branch_party + # remove_index :accounts, name: :by_branch_party def remove_index(table_name, options = {}) remove_index!(table_name, index_name_for_remove(table_name, options)) end @@ -422,7 +422,7 @@ module ActiveRecord end def index_name(table_name, options) #:nodoc: - if Hash === options # legacy support + if Hash === options if options[:column] "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}" elsif options[:name] @@ -617,15 +617,26 @@ module ActiveRecord def add_index_options(table_name, column_name, options = {}) column_names = Array(column_name) - index_name = index_name(table_name, :column => column_names) + index_name = index_name(table_name, column: column_names) if Hash === options # legacy support, since this param was a string + options.assert_valid_keys(:unique, :order, :name, :where, :length) + index_type = options[:unique] ? "UNIQUE" : "" index_name = options[:name].to_s if options.key?(:name) + if supports_partial_index? index_options = options[:where] ? " WHERE #{options[:where]}" : "" end else + if options + message = "Passing a string as third argument of `add_index` is deprecated and will" + + " be removed in Rails 4.1." + + " Use add_index(#{table_name.inspect}, #{column_name.inspect}, unique: true) instead" + + ActiveSupport::Deprecation.warn message + end + index_type = options end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 2c57b52017..84e73e6f0f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -353,9 +353,9 @@ module ActiveRecord # Charset defaults to utf8. # # Example: - # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin' + # create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin' # create_database 'matt_development' - # create_database 'matt_development', :charset => :big5 + # create_database 'matt_development', charset: :big5 def create_database(name, options = {}) if options[:collation] execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`" diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 879eec7fcf..f55d19393c 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -175,7 +175,7 @@ module ActiveRecord # # as values. # def select_one(sql, name = nil) # result = execute(sql, name) - # result.each(:as => :hash) do |r| + # result.each(as: :hash) do |r| # return r # end # end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 7cad8f94cf..82a0b662f4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -16,7 +16,7 @@ module ActiveRecord # # Example: # create_database config[:database], config - # create_database 'foo_development', :encoding => 'unicode' + # create_database 'foo_development', encoding: 'unicode' def create_database(name, options = {}) options = options.reverse_merge(:encoding => "utf8") diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 0637dd58b6..04c0fbfe70 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -193,6 +193,17 @@ module ActiveRecord end + # Raised when a relation cannot be mutated because it's already loaded. + # + # class Task < ActiveRecord::Base + # end + # + # relation = Task.all + # relation.loaded? # => true + # + # # Methods which try to mutate a loaded relation fail. + # relation.where!(title: 'TODO') # => ActiveRecord::ImmutableRelation + # relation.limit!(5) # => ActiveRecord::ImmutableRelation class ImmutableRelation < ActiveRecordError end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 6bc5cd1fb9..29a99a5336 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -657,6 +657,7 @@ module ActiveRecord #-- # Deprecate 'Fixtures' in favor of 'FixtureSet'. #++ + # :nodoc: Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet') class Fixture #:nodoc: diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 5499f37802..22347fcaef 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -32,7 +32,7 @@ module ActiveRecord class PendingMigrationError < ActiveRecordError#:nodoc: def initialize - super("Migrations are pending run 'rake db:migrate RAILS_ENV=#{ENV['RAILS_ENV']}' to resolve the issue") + super("Migrations are pending; run 'rake db:migrate RAILS_ENV=#{ENV['RAILS_ENV']}' to resolve this issue.") end end @@ -642,7 +642,11 @@ module ActiveRecord def proper_table_name(name) # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string - name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" + if name.respond_to? :table_name + name.table_name + else + "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" + end end def migrations_paths diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index d026c50ee6..aba56c2861 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -105,7 +105,7 @@ module ActiveRecord # ] # }} # - # member = Member.create(params['member']) + # member = Member.create(params[:member]) # member.posts.length # => 2 # member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!' # member.posts.second.title # => 'The egalitarian assumption of the modern citizen' @@ -127,7 +127,7 @@ module ActiveRecord # ] # }} # - # member = Member.create(params['member']) + # member = Member.create(params[:member]) # member.posts.length # => 2 # member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!' # member.posts.second.title # => 'The egalitarian assumption of the modern citizen' @@ -177,7 +177,7 @@ module ActiveRecord # :posts_attributes => [{ :id => '2', :_destroy => '1' }] # }} # - # member.attributes = params['member'] + # member.attributes = params[:member] # member.posts.detect { |p| p.id == 2 }.marked_for_destruction? # => true # member.posts.length # => 2 # member.save diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index c336e1f5bb..8e749772a1 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -15,18 +15,18 @@ module ActiveRecord # # ==== Examples # # Create a single new object - # User.create(:first_name => 'Jamie') + # User.create(first_name: 'Jamie') # # # Create an Array of new objects - # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) + # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) # # # Create a single object and pass it into a block to set other attributes. - # User.create(:first_name => 'Jamie') do |u| + # User.create(first_name: 'Jamie') do |u| # u.is_admin = false # end # # # Creating an Array of new objects using a block, where the block is executed for each object: - # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u| + # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u| # u.is_admin = false # end def create(attributes = nil, &block) @@ -64,7 +64,7 @@ module ActiveRecord # # By default, save always run validations. If any of them fail the action # is cancelled and +save+ returns +false+. However, if you supply - # :validate => false, validations are bypassed altogether. See + # validate: false, validations are bypassed altogether. See # ActiveRecord::Validations for more information. # # There's a series of callbacks associated with +save+. If any of the @@ -143,7 +143,7 @@ module ActiveRecord # inheritance structures where you want a subclass to appear as the # superclass. This can be used along with record identification in # Action Pack to allow, say, <tt>Client < Company</tt> to do something - # like render <tt>:partial => @client.becomes(Company)</tt> to render that + # like render <tt>partial: @client.becomes(Company)</tt> to render that # instance using the companies/company partial instead of clients/client. # # Note: The new instance will share a link to the same attributes as the original class. @@ -286,7 +286,7 @@ module ActiveRecord # Reloads the attributes of this object from the database. # The optional options argument is passed to find when reloading so you - # may do e.g. record.reload(:lock => true) to reload the same record with + # may do e.g. record.reload(lock: true) to reload the same record with # an exclusive row lock. def reload(options = nil) clear_aggregation_cache @@ -317,11 +317,11 @@ module ActiveRecord # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object. # # class Brake < ActiveRecord::Base - # belongs_to :car, :touch => true + # belongs_to :car, touch: true # end # # class Car < ActiveRecord::Base - # belongs_to :corporation, :touch => true + # belongs_to :corporation, touch: true # end # # # triggers @brake.car.touch and @brake.car.corporation.touch diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index f322b96f79..0103de4cbd 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -81,13 +81,13 @@ module ActiveRecord class MacroReflection # Returns the name of the macro. # - # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>:balance</tt> + # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:balance</tt> # <tt>has_many :clients</tt> returns <tt>:clients</tt> attr_reader :name # Returns the macro type. # - # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>:composed_of</tt> + # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:composed_of</tt> # <tt>has_many :clients</tt> returns <tt>:has_many</tt> attr_reader :macro @@ -95,7 +95,7 @@ module ActiveRecord # Returns the hash of options used for the macro. # - # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>{ :class_name => "Money" }</tt> + # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>{ class_name: "Money" }</tt> # <tt>has_many :clients</tt> returns +{}+ attr_reader :options @@ -115,7 +115,7 @@ module ActiveRecord # Returns the class for the macro. # - # <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money class + # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class # <tt>has_many :clients</tt> returns the Client class def klass @klass ||= class_name.constantize @@ -123,7 +123,7 @@ module ActiveRecord # Returns the class name for the macro. # - # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>'Money'</tt> + # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt> # <tt>has_many :clients</tt> returns <tt>'Client'</tt> def class_name @class_name ||= (options[:class_name] || derive_class_name).to_s @@ -315,10 +315,10 @@ module ActiveRecord # the parent's validation. # # Unless you explicitly disable validation with - # <tt>:validate => false</tt>, validation will take place when: + # <tt>validate: false</tt>, validation will take place when: # - # * you explicitly enable validation; <tt>:validate => true</tt> - # * you use autosave; <tt>:autosave => true</tt> + # * you explicitly enable validation; <tt>validate: true</tt> + # * you use autosave; <tt>autosave: true</tt> # * the association is a +has_many+ association def validate? !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many) @@ -399,7 +399,7 @@ module ActiveRecord # # class Post < ActiveRecord::Base # has_many :taggings - # has_many :tags, :through => :taggings + # has_many :tags, through: :taggings # end # def source_reflection @@ -411,7 +411,7 @@ module ActiveRecord # # class Post < ActiveRecord::Base # has_many :taggings - # has_many :tags, :through => :taggings + # has_many :tags, through: :taggings # end # # tags_reflection = Post.reflect_on_association(:tags) @@ -439,12 +439,12 @@ module ActiveRecord # # class Person # has_many :articles - # has_many :comment_tags, :through => :articles + # has_many :comment_tags, through: :articles # end # # class Article # has_many :comments - # has_many :comment_tags, :through => :comments, :source => :tags + # has_many :comment_tags, through: :comments, source: :tags # end # # class Comment diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 2e2286e4fd..cb9cc5a9df 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -235,7 +235,7 @@ module ActiveRecord # Scope all queries to the current scope. # - # Comment.where(:post_id => 1).scoping do + # Comment.where(post_id: 1).scoping do # Comment.first # SELECT * FROM comments WHERE post_id = 1 # end # @@ -266,7 +266,7 @@ module ActiveRecord # Book.where('title LIKE ?', '%Rails%').update_all(author: 'David') # # # Update all books that match conditions, but limit it to 5 ordered by date - # Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(:author => 'David') + # Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David') def update_all(updates) raise ArgumentError, "Empty list of attributes to change" if updates.blank? @@ -339,7 +339,7 @@ module ActiveRecord # # Person.destroy_all("last_login < '2004-04-04'") # Person.destroy_all(status: "inactive") - # Person.where(:age => 0..18).destroy_all + # Person.where(age: 0..18).destroy_all def destroy_all(conditions = nil) if conditions where(conditions).destroy_all @@ -384,7 +384,7 @@ module ActiveRecord # # Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')") # Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else']) - # Post.where(:person_id => 5).where(:category => ['Something', 'Else']).delete_all + # Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all # # Both calls delete the affected posts all at once with a single DELETE statement. # If you need to destroy dependent associations or call your <tt>before_*</tt> or @@ -514,7 +514,7 @@ module ActiveRecord # Joins that are also marked for preloading. In which case we should just eager load them. # Note that this is a naive implementation because we could have strings and symbols which # represent the same association, but that aren't matched by this. Also, we could have - # nested hashes which partially match, e.g. { :a => :b } & { :a => [:b, :c] } + # nested hashes which partially match, e.g. { a: :b } & { a: [:b, :c] } def joined_includes_values includes_values & joins_values end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 99c2f45bc8..af67b2ba6c 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/hash/indifferent_access' - module ActiveRecord module FinderMethods # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). @@ -225,7 +223,7 @@ module ActiveRecord def construct_limited_ids_condition(relation) orders = relation.order_values.map { |val| val.presence }.compact - values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders) + values = @klass.connection.distinct("#{quoted_table_name}.#{primary_key}", orders) relation = relation.dup @@ -234,8 +232,6 @@ module ActiveRecord end def find_with_ids(*ids) - return to_a.find { |*block_args| yield(*block_args) } if block_given? - expects_array = ids.first.kind_of?(Array) return ids.first if expects_array && ids.first.empty? diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 4fdc296c7e..0817bb6d81 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -218,7 +218,6 @@ module ActiveRecord # Like #order, but modifies relation in place. def order!(*args) args.flatten! - validate_order_args args references = args.reject { |arg| Arel::Node === arg } @@ -245,7 +244,6 @@ module ActiveRecord # Like #reorder, but modifies relation in place. def reorder!(*args) args.flatten! - validate_order_args args self.reordering_value = true @@ -796,7 +794,7 @@ module ActiveRecord def reverse_sql_order(order_query) order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty? - order_query.map do |o| + order_query.flat_map do |o| case o when Arel::Nodes::Ordering o.reverse @@ -814,7 +812,7 @@ module ActiveRecord else o end - end.flatten + end end def array_of_strings?(o) @@ -825,7 +823,7 @@ module ActiveRecord orders = order_values orders = reverse_sql_order(orders) if reverse_order_value - orders = orders.uniq.reject(&:blank?).map do |order| + orders = orders.uniq.reject(&:blank?).flat_map do |order| case order when Symbol table[order].asc @@ -834,7 +832,7 @@ module ActiveRecord else order end - end.flatten + end arel.order(*orders) unless orders.empty? end |