diff options
51 files changed, 577 insertions, 307 deletions
@@ -11,11 +11,9 @@ gem 'rake', '>= 10.3' gem 'mocha', '~> 0.14', require: false gem 'rack-cache', '~> 1.2' -gem 'jquery-rails', '~> 4.0.0.beta2' +gem 'jquery-rails', '~> 4.0' gem 'coffee-rails', '~> 4.1.0' gem 'turbolinks' -gem 'arel', github: 'rails/arel' -gem 'rails-dom-testing', github: 'rails/rails-dom-testing' # require: false so bcrypt is loaded only when has_secure_password is used. # This is to avoid ActiveModel (and by extension the entire framework) diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index abc047d339..b63f4e5c08 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -24,5 +24,5 @@ Gem::Specification.new do |s| s.add_dependency 'activejob', version s.add_dependency 'mail', ['~> 2.5', '>= 2.5.4'] - s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.4' + s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.5' end diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 5196e67e55..1e68d1870d 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_dependency 'rack', '~> 1.6.0.beta' s.add_dependency 'rack-test', '~> 0.6.2' s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.1' - s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.4' + s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.5' s.add_dependency 'actionview', version s.add_development_dependency 'activemodel', version diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 7bbf938987..5cb11bc479 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -44,7 +44,7 @@ module ActionController # The full request object is available via the request accessor and is primarily used to query for HTTP headers: # # def server_ip - # location = request.env["SERVER_ADDR"] + # location = request.env["REMOTE_ADDR"] # render plain: "This server hosted at #{location}" # end # diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb index 89fa75f025..d3f93a5352 100644 --- a/actionpack/lib/action_controller/log_subscriber.rb +++ b/actionpack/lib/action_controller/log_subscriber.rb @@ -1,4 +1,3 @@ - module ActionController class LogSubscriber < ActiveSupport::LogSubscriber INTERNAL_PARAMS = %w(controller action format _method only_path) diff --git a/actionpack/lib/action_dispatch/journey/visualizer/fsm.css b/actionpack/lib/action_dispatch/journey/visualizer/fsm.css index 50caebaa18..403e16a7bb 100644 --- a/actionpack/lib/action_dispatch/journey/visualizer/fsm.css +++ b/actionpack/lib/action_dispatch/journey/visualizer/fsm.css @@ -16,10 +16,6 @@ h2 { font-size: 0.5em; } -div#chart-2 { - height: 350px; -} - .clearfix {display: inline-block; } .input { overflow: show;} .instruction { color: #666; padding: 0 30px 20px; font-size: 0.9em} diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 7a91674c3c..a7f95150a4 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -79,7 +79,7 @@ module ActionDispatch class FlashHash include Enumerable - def self.from_session_value(value) + def self.from_session_value(value) #:nodoc: flash = case value when FlashHash # Rails 3.1, 3.2 new(value.instance_variable_get(:@flashes), value.instance_variable_get(:@used)) @@ -91,8 +91,11 @@ module ActionDispatch flash.tap(&:sweep) end - - def to_session_value + + # Builds a hash containing the discarded values and the hashes + # representing the flashes. + # If there are no values in @flashes, returns nil. + def to_session_value #:nodoc: return nil if empty? {'discard' => @discard.to_a, 'flashes' => @flashes} end diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index b426183488..29d43faeed 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -47,7 +47,7 @@ module ActionDispatch else false end - rescue Exception => e # JSON or Ruby code block errors + rescue => e # JSON or Ruby code block errors logger(env).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}" raise ParseError.new(e.message, e) diff --git a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb index 6ffa242da4..5cee0b5932 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb @@ -1,6 +1,6 @@ <% content_for :style do %> #route_table { - margin: 0 auto 0; + margin: 0; border-collapse: collapse; } diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index be54d43172..a8be77f46d 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -244,12 +244,10 @@ module ActionDispatch def app(blocks) if to.respond_to?(:call) Constraints.new(to, blocks, false) + elsif blocks.any? + Constraints.new(dispatcher(defaults), blocks, true) else - if blocks.any? - Constraints.new(dispatcher(defaults), blocks, true) - else - dispatcher(defaults) - end + dispatcher(defaults) end end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index dcfb819906..6e3ae36a7f 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -749,7 +749,7 @@ module ActionDispatch end def find_script_name(options) - options.delete(:script_name) { '' } + options.delete(:script_name) || '' end def path_for(options, route_name = nil) # :nodoc: diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index f0eba17556..0ffa2d2a03 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -290,6 +290,13 @@ module AbstractController end end + def test_using_nil_script_name_properly_concats_with_original_script_name + add_host! + assert_equal('https://www.basecamphq.com/subdir/c/a/i', + W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https', :script_name => nil, :original_script_name => '/subdir') + ) + end + def test_only_path with_routing do |set| set.draw do diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index d80b0e2da0..2b109ff19e 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -83,6 +83,16 @@ class WebServiceTest < ActionDispatch::IntegrationTest end end + def test_parsing_json_doesnot_rescue_exception + with_test_route_set do + with_params_parsers Mime::JSON => Proc.new { |data| raise Interrupt } do + assert_raises(Interrupt) do + post "/", '{"title":"JSON"}}', 'CONTENT_TYPE' => 'application/json' + end + end + end + end + private def with_params_parsers(parsers = {}) old_session = @integration_session diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 6b7adbe4a3..de65543137 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,10 @@ +* Local variable in a partial is now available even if a falsy value is + passed to `:object` when rendering a partial. + + Fixes #17373. + + *Agis Anastasopoulos* + * Add support for `:enforce_utf8` option in `form_for`. This is the same option that was added in 06388b0 to `form_tag` and allows diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec index 70efe7e8c2..28407521cc 100644 --- a/actionview/actionview.gemspec +++ b/actionview/actionview.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_dependency 'builder', '~> 3.1' s.add_dependency 'erubis', '~> 2.7.0' s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.1' - s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.4' + s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.5' s.add_development_dependency 'actionpack', version s.add_development_dependency 'activemodel', version diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb index 0407632435..f627d5d40c 100644 --- a/actionview/lib/action_view/renderer/partial_renderer.rb +++ b/actionview/lib/action_view/renderer/partial_renderer.rb @@ -366,10 +366,12 @@ module ActionView partial = options[:partial] if String === partial + @has_object = options.key?(:object) @object = options[:object] @collection = collection_from_options @path = partial else + @has_object = true @object = partial @collection = collection_from_object || collection_from_options @@ -506,7 +508,7 @@ module ActionView def retrieve_template_keys keys = @locals.keys - keys << @variable if @object || @collection + keys << @variable if @has_object || @collection if @collection keys << @variable_counter keys << @variable_iteration diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 9130cfbe9e..a6ed8cdb06 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,18 @@ +* Bring back `db:test:prepare` to synchronize the test database schema. + + Manual synchronization using `bin/rake db:test:prepare` is required + when a migration is rolled-back, edited and reapplied. + + `ActiveRecord::Base.maintain_test_schema` now uses `db:test:prepare` + to synchronize the schema. Plugins can use this task as a hook to + provide custom behavior after the schema has been loaded. + + NOTE: `test:prepare` runs before the schema is synchronized. + + Fixes #17171, #15787. + + *Yves Senn* + * Change `reflections` public api to return the keys as String objects. Fixes #16928. @@ -14,12 +29,11 @@ *Yves Senn* -* Fix includes on association with a scope containing joins along with conditions - on the joined assoiciation. +* Fix preloading of associations with a scope containing joins along with + conditions on the joined association. *Siddharth Sharma* - * Add `Table#name` to match `TableDefinition#name`. *Cody Cutrer* @@ -80,7 +94,7 @@ *Yuki Nishijima* -* Fix regression causing `after_create` callbacks to run before associated +* Fix a regression causing `after_create` callbacks to run before associated records are autosaved. Fixes #17209. @@ -177,7 +191,7 @@ *Yves Senn* -* Fixed a regression where whitespaces were stripped from DISTINCT queries in +* Fix a regression where whitespaces were stripped from DISTINCT queries in PostgreSQL. *Agis Anastasopoulos* @@ -191,7 +205,7 @@ *Agis Anastasopoulos* -* Fixed `Relation#exists?` to work with polymorphic associations. +* Fix `Relation#exists?` to work with polymorphic associations. Fixes #15821. @@ -213,7 +227,7 @@ *arthurnn* -* Fixed an issue where custom accessor methods (such as those generated by +* Fix an issue where custom accessor methods (such as those generated by `enum`) with the same name as a global method are incorrectly overridden when subclassing. @@ -277,7 +291,7 @@ *Yves Senn* -* Fixed automatic maintaining test schema to properly handle sql structure +* Fix automatic maintaining test schema to properly handle sql structure schema format. Fixes #15394. @@ -440,8 +454,8 @@ *Sean Griffin* -* Fixed error in `reset_counters` when associations have `select` scope. - (Call to `count` generates invalid SQL.) +* Fix an error in `reset_counters` when associations have `select` scope. + (Call to `count` generated invalid SQL.) *Cade Truitt* @@ -666,7 +680,7 @@ *Yves Senn* -* Fixed `columns_for_distinct` of postgresql adapter to work correctly +* Fix `columns_for_distinct` of PostgreSQL adapter to work correctly with orders without sort direction modifiers. *Nikolay Kondratyev* @@ -702,7 +716,7 @@ *arthurnn* -* Fixed serialization for records with an attribute named `format`. +* Fix serialization for records with an attribute named `format`. Fixes #15188. @@ -713,12 +727,12 @@ *Kuldeep Aggarwal* -* Fixed serialized fields returning serialized data after being updated with +* Fix serialized fields returning serialized data after being updated with `update_column`. *Simon Hørup Eskildsen* -* Fixed polymorphic eager loading when using a String as foreign key. +* Fix polymorphic eager loading when using a String as foreign key. Fixes #14734. @@ -732,7 +746,7 @@ *Brock Trappitt* -* Fixed the inferred table name of a `has_and_belongs_to_many` auxiliar +* Fix the inferred table name of a `has_and_belongs_to_many` auxiliary table inside a schema. Fixes #14824. @@ -844,7 +858,7 @@ *Yves Senn* -* Fixed has_and_belongs_to_many's CollectionAssociation size calculation. +* Fix `has_and_belongs_to_many` CollectionAssociation size calculations. `has_and_belongs_to_many` should fall back to using the normal CollectionAssociation's size calculation if the collection is not cached or loaded. @@ -949,10 +963,12 @@ *Earl St Sauver* -* Fixed unexpected behavior for `has_many :through` associations going through a scoped `has_many`. +* Fix unexpected behavior for `has_many :through` associations going through + a scoped `has_many`. - If a `has_many` association is adjusted using a scope, and another `has_many :through` - uses this association, then the scope adjustment is unexpectedly neglected. + If a `has_many` association is adjusted using a scope, and another + `has_many :through` uses this association, then the scope adjustment is + unexpectedly neglected. Fixes #14537. @@ -962,13 +978,13 @@ *Kuldeep Aggarwal* -* Fixed `has_many` association to make it support irregular inflections. +* Enable `has_many` associations to support irregular inflections. Fixes #8928. *arthurnn*, *Javier Goizueta* -* Fixed a problem where count used with a grouping was not returning a Hash. +* Fix `count` used with a grouping not returning a Hash. Fixes #14721. @@ -1023,8 +1039,8 @@ *Eileen M. Uchitelle*, *Aaron Patterson* -* Fixed error for aggregate methods (`empty?`, `any?`, `count`) with `select` - which created invalid SQL. +* Fix invalid SQL when aggregate methods (`empty?`, `any?`, `count`) used + with `select`. Fixes #13648. @@ -1055,8 +1071,8 @@ *Roderick van Domburg* -* Fixed a problem where an enum would overwrite values of another enum - with the same name in an unrelated class. +* Fix a problem where an enum would overwrite values of another enum with the + same name in an unrelated class. Fixes #14607. @@ -1091,7 +1107,7 @@ *arthurnn* -* Fixed error when using `with_options` with lambda. +* Fix error when using `with_options` with lambda. Fixes #9805. @@ -1129,14 +1145,15 @@ *Yves Senn* -* Fixed error when specifying a non-empty default value on a PostgreSQL array column. +* Fix error when specifying a non-empty default value on a PostgreSQL array + column. Fixes #10613. *Luke Steensen* -* Fixed error where .persisted? throws SystemStackError for an unsaved model with a - custom primary key that didn't save due to validation error. +* Fix error where `.persisted?` throws SystemStackError for an unsaved model with a + custom primary key that did not save due to validation error. Fixes #14393. @@ -1229,7 +1246,8 @@ *Aaron Patterson* -* Only use BINARY for MySQL case sensitive uniqueness check when column has a case insensitive collation. +* Only use BINARY for MySQL case sensitive uniqueness check when column + has a case insensitive collation. *Ryuta Kamizono* @@ -1237,8 +1255,8 @@ *arthurnn*, *Tatsuhiko Miyagawa* -* Support for Postgres `citext` data type enabling case-insensitive where - values without needing to wrap in UPPER/LOWER sql functions. +* Support for PostgreSQL `citext` data type enabling case-insensitive + `where` values without needing to wrap in UPPER/LOWER sql functions. *Troy Kruthoff*, *Lachlan Sylvester* @@ -1268,9 +1286,8 @@ *Aaron Patterson*, *Yves Senn* -* Fixed error with validation with enum fields for records where the - value for any enum attribute is always evaluated as 0 during - uniqueness validation. +* Fix error with validation with enum fields for records where the value for + any enum attribute is always evaluated as 0 during uniqueness validation. Fixes #14172. @@ -1284,8 +1301,8 @@ Fixes #14144. -* Fixed STI classes not defining an attribute method if there is a - conflicting private method defined on its ancestors. +* Fix STI classes not defining an attribute method if there is a conflicting + private method defined on its ancestors. Fixes #11569. diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index bc10e96244..834fffeb18 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -24,5 +24,5 @@ Gem::Specification.new do |s| s.add_dependency 'activesupport', version s.add_dependency 'activemodel', version - s.add_dependency 'arel', '>= 6.0.0.beta2', '< 6.1' + s.add_dependency 'arel', '~> 6.0' end diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index a6a1947148..0c3234ed24 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -57,20 +57,10 @@ module ActiveRecord end def aliased_table_for(table_name, aliased_name) - table_alias = aliased_name_for(table_name, aliased_name) - - if table_alias == table_name - Arel::Table.new(table_name) - else - Arel::Table.new(table_name).alias(table_alias) - end - end - - def aliased_name_for(table_name, aliased_name) if aliases[table_name].zero? # If it's zero, we can have our table_name aliases[table_name] = 1 - table_name + Arel::Table.new(table_name) else # Otherwise, we need to use an alias aliased_name = connection.table_alias_for(aliased_name) @@ -78,11 +68,12 @@ module ActiveRecord # Update the count aliases[aliased_name] += 1 - if aliases[aliased_name] > 1 + table_alias = if aliases[aliased_name] > 1 "#{truncate(aliased_name)}_#{aliases[aliased_name]}" else aliased_name end + Arel::Table.new(table_name).alias(table_alias) end end diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index d59cebb08b..2b7d39893d 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -358,6 +358,7 @@ module ActiveRecord if owner.new_record? replace_records(other_array, original_target) else + replace_common_records_in_memory(other_array, original_target) if other_array != original_target transaction { replace_records(other_array, original_target) } end @@ -385,11 +386,18 @@ module ActiveRecord target end - def add_to_target(record, skip_callbacks = false) + def add_to_target(record, skip_callbacks = false, &block) + if association_scope.distinct_value + index = @target.index(record) + end + replace_on_target(record, index, skip_callbacks, &block) + end + + def replace_on_target(record, index, skip_callbacks) callback(:before_add, record) unless skip_callbacks yield(record) if block_given? - if association_scope.distinct_value && index = @target.index(record) + if index @target[index] = record else @target << record @@ -534,6 +542,14 @@ module ActiveRecord target end + def replace_common_records_in_memory(new_target, original_target) + common_records = new_target & original_target + common_records.each do |record| + skip_callbacks = true + replace_on_target(record, @target.index(record), skip_callbacks) + end + end + def concat_records(records, should_raise = false) result = true diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index c5c4edd090..285d0ec9af 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -94,7 +94,7 @@ module ActiveRecord # def initialize(base, associations, joins) @alias_tracker = AliasTracker.create(base.connection, joins) - @alias_tracker.aliased_name_for(base.table_name, base.table_name) # Updates the count for base.table_name to 1 + @alias_tracker.aliased_table_for(base.table_name, base.table_name) # Updates the count for base.table_name to 1 tree = self.class.make_tree associations @join_root = JoinBase.new base, build(tree, base) @join_root.children.each { |child| construct_tables! @join_root, child } diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index f95f45c689..991c41327f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -14,22 +14,6 @@ module ActiveRecord @connection.unescape_bytea(value) if value end - # Quotes PostgreSQL-specific data types for SQL input. - def quote(value, column = nil) #:nodoc: - return super unless column - - case value - when Float - if value.infinite? || value.nan? - "'#{value}'" - else - super - end - else - super - end - end - # Quotes strings for use in SQL input. def quote_string(s) #:nodoc: @connection.escape(s) @@ -94,6 +78,12 @@ module ActiveRecord elsif value.hex? "X'#{value}'" end + when Float + if value.infinite? || value.nan? + "'#{value}'" + else + super + end else super end diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 5b3fdf16f5..ca4fede7a2 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -52,10 +52,29 @@ module ActiveRecord # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be # saved because record is invalid. class RecordNotSaved < ActiveRecordError + attr_reader :record + + def initialize(record) + @record = record + super() + end end # Raised by ActiveRecord::Base.destroy! when a call to destroy would return false. + # + # begin + # complex_operation_that_internally_calls_destroy! + # rescue ActiveRecord::RecordNotDestroyed => invalid + # puts invalid.record.errors + # end + # class RecordNotDestroyed < ActiveRecordError + attr_reader :record + + def initialize(record) + @record = record + super() + end end # Superclass for all database execution errors. diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 4e00eb3d99..92f2951f2d 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -395,7 +395,14 @@ module ActiveRecord def load_schema_if_pending! if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations? - ActiveRecord::Tasks::DatabaseTasks.load_schema_current_if_exists + # Roundrip to Rake to allow plugins to hook into database initialization. + FileUtils.cd Rails.root do + current_config = Base.connection_config + Base.clear_all_connections! + system("bin/rake db:test:prepare") + # Establish a new connection, the old database may be gone (db:test:prepare uses purge) + Base.establish_connection(current_config) + end check_pending! end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index ee3b7b6163..8d84a3acae 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -139,7 +139,7 @@ module ActiveRecord # Attributes marked as readonly are silently ignored if the record is # being updated. def save!(*) - create_or_update || raise(RecordNotSaved) + create_or_update || raise(RecordNotSaved, self) end # Deletes the record in the database and freezes this instance to @@ -181,7 +181,7 @@ module ActiveRecord # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See # ActiveRecord::Callbacks for further details. def destroy! - destroy || raise(ActiveRecord::RecordNotDestroyed) + destroy || raise(ActiveRecord::RecordNotDestroyed, self) end # Returns an instance of the specified +klass+ with the attributes of the diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index a4ceacbf44..f1bdbc845c 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -36,8 +36,6 @@ module ActiveRecord config.eager_load_namespaces << ActiveRecord rake_tasks do - require "active_record/base" - namespace :db do task :load_config do ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 3ec25f9f17..21b1c3f721 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -305,7 +305,7 @@ db_namespace = namespace :db do end # desc "Recreate the test database from the current schema" - task :load => %w(db:test:deprecated db:test:purge) do + task :load => %w(db:test:purge) do case ActiveRecord::Base.schema_format when :ruby db_namespace["test:load_schema"].invoke @@ -315,7 +315,7 @@ db_namespace = namespace :db do end # desc "Recreate the test database from an existent schema.rb file" - task :load_schema => %w(db:test:deprecated db:test:purge) do + task :load_schema => %w(db:test:purge) do begin should_reconnect = ActiveRecord::Base.connection_pool.active_connection? ActiveRecord::Schema.verbose = false @@ -328,7 +328,7 @@ db_namespace = namespace :db do end # desc "Recreate the test database from an existent structure.sql file" - task :load_structure => %w(db:test:deprecated db:test:purge) do + task :load_structure => %w(db:test:purge) do ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA'] end @@ -349,12 +349,12 @@ db_namespace = namespace :db do task :clone_structure => %w(db:test:deprecated db:structure:dump db:test:load_structure) # desc "Empty the test database" - task :purge => %w(db:test:deprecated environment load_config) do + task :purge => %w(environment load_config) do ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test'] end # desc 'Check for pending migrations and load the test schema' - task :prepare => %w(db:test:deprecated environment load_config) do + task :prepare => %w(environment load_config) do unless ActiveRecord::Base.configurations.blank? db_namespace['test:load'].invoke end diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 261fb9d992..1dd2cadc01 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -244,12 +244,7 @@ HEADER def ignored?(table_name) ['schema_migrations', ignore_tables].flatten.any? do |ignored| - case ignored - when String; remove_prefix_and_suffix(table_name) == ignored - when Regexp; remove_prefix_and_suffix(table_name) =~ ignored - else - raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.' - end + ignored === remove_prefix_and_suffix(table_name) end end end diff --git a/activerecord/lib/active_record/type/integer.rb b/activerecord/lib/active_record/type/integer.rb index 36bbd9cd5e..750f353472 100644 --- a/activerecord/lib/active_record/type/integer.rb +++ b/activerecord/lib/active_record/type/integer.rb @@ -38,7 +38,7 @@ module ActiveRecord def ensure_in_range(value) unless range.cover?(value) - raise RangeError, "#{value} is too large for #{self.class} with limit #{limit || 4}" + raise RangeError, "#{value} is out of range for #{self.class} with limit #{limit || 4}" end end 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 f7bf6987c4..fb0fbb4759 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 @@ -15,5 +15,8 @@ class <%= migration_class_name %> < ActiveRecord::Migration <% attributes_with_index.each do |attribute| -%> add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %> <% end -%> +<% attributes.select(&:reference?).reject(&:polymorphic?).each do |attribute| -%> + add_foreign_key :<%= table_name %>, :<%= attribute.name.pluralize %> +<% end -%> end 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..7df9bcad25 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 %> + <%- unless attribute.polymorphic? -%> + add_foreign_key :<%= table_name %>, :<%= attribute.name.pluralize %> + <%- end -%> <%- else -%> add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %> <%- if attribute.has_index? -%> @@ -26,6 +29,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration <%- if migration_action -%> <%- if attribute.reference? -%> remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %> + <%- unless attribute.polymorphic? -%> + remove_foreign_key :<%= table_name %>, :<%= attribute.name.pluralize %> + <%- end -%> <%- else -%> <%- if attribute.has_index? -%> remove_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %> diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 5a963b6458..8b7ab11570 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1997,4 +1997,68 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, car.bulbs.count assert_equal 1, car.tyres.count end + + test 'associations replace in memory when records have the same id' do + bulb = Bulb.create! + car = Car.create!(bulbs: [bulb]) + + new_bulb = Bulb.find(bulb.id) + new_bulb.name = "foo" + car.bulbs = [new_bulb] + + assert_equal "foo", car.bulbs.first.name + end + + test 'in memory replacement executes no queries' do + bulb = Bulb.create! + car = Car.create!(bulbs: [bulb]) + + new_bulb = Bulb.find(bulb.id) + + assert_no_queries do + car.bulbs = [new_bulb] + end + end + + test 'in memory replacements do not execute callbacks' do + raise_after_add = false + klass = Class.new(ActiveRecord::Base) do + self.table_name = :cars + has_many :bulbs, after_add: proc { raise if raise_after_add } + + def self.name + "Car" + end + end + bulb = Bulb.create! + car = klass.create!(bulbs: [bulb]) + + new_bulb = Bulb.find(bulb.id) + raise_after_add = true + + assert_nothing_raised do + car.bulbs = [new_bulb] + end + end + + test 'in memory replacements sets inverse instance' do + bulb = Bulb.create! + car = Car.create!(bulbs: [bulb]) + + new_bulb = Bulb.find(bulb.id) + car.bulbs = [new_bulb] + + assert_same car, new_bulb.car + end + + test 'in memory replacement maintains order' do + first_bulb = Bulb.create! + second_bulb = Bulb.create! + car = Car.create!(bulbs: [first_bulb, second_bulb]) + + same_bulb = Bulb.find(first_bulb.id) + car.bulbs = [second_bulb, same_bulb] + + assert_equal [first_bulb, second_bulb], car.bulbs + end end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index 5e07f8a03c..e3c3c2fcdf 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -443,7 +443,8 @@ class CallbacksTest < ActiveRecord::TestCase david = ImmutableDeveloper.find(1) assert david.valid? assert !david.save - assert_raise(ActiveRecord::RecordNotSaved) { david.save! } + exc = assert_raise(ActiveRecord::RecordNotSaved) { david.save! } + assert_equal exc.record, david david = ImmutableDeveloper.find(1) david.salary = 10_000_000 @@ -477,7 +478,8 @@ class CallbacksTest < ActiveRecord::TestCase def test_before_destroy_returning_false david = ImmutableDeveloper.find(1) assert !david.destroy - assert_raise(ActiveRecord::RecordNotDestroyed) { david.destroy! } + exc = assert_raise(ActiveRecord::RecordNotDestroyed) { david.destroy! } + assert_equal exc.record, david assert_not_nil ImmutableDeveloper.find_by_id(1) someone = CallbackCancellationDeveloper.find(1) diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 6303393c22..8731531f54 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -162,16 +162,6 @@ class SchemaDumperTest < ActiveRecord::TestCase assert_no_match %r{create_table "schema_migrations"}, output end - def test_schema_dump_illegal_ignored_table_value - stream = StringIO.new - old_ignore_tables, ActiveRecord::SchemaDumper.ignore_tables = ActiveRecord::SchemaDumper.ignore_tables, [5] - assert_raise(StandardError) do - ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream) - end - ensure - ActiveRecord::SchemaDumper.ignore_tables = old_ignore_tables - end - def test_schema_dumps_index_columns_in_right_order index_definition = standard_dump.split(/\n/).grep(/add_index.*companies/).first.strip if current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter) diff --git a/guides/Rakefile b/guides/Rakefile index 94d4be8c0a..824bea0b39 100644 --- a/guides/Rakefile +++ b/guides/Rakefile @@ -34,10 +34,12 @@ namespace :guides do task :help do puts <<-help -Guides are taken from the source directory, and the resulting HTML goes into the +Guides are taken from the source directory, and the result goes into the output directory. Assets are stored under files, and copied to output/files as part of the generation process. +You can generate HTML, Kindle or both formats using the `guides:generate` task. + All this process is handled via rake tasks, here's a full list of them: #{%x[rake -T]} diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index 2630207c0f..e985f1ab4b 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -138,7 +138,7 @@ More Information: - [Rails Edge Architecture](http://yehudakatz.com/2009/06/11/r [Arel](http://github.com/brynary/arel) (or Active Relation) has been taken on as the underpinnings of Active Record and is now required for Rails. Arel provides an SQL abstraction that simplifies out Active Record and provides the underpinnings for the relation functionality in Active Record. -More information: - [Why I wrote Arel](http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/.) +More information: - [Why I wrote Arel](https://web.archive.org/web/20120718093140/http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/) ### Mail Extraction diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md index 0281213bf2..87a4f8b463 100644 --- a/guides/source/4_2_release_notes.md +++ b/guides/source/4_2_release_notes.md @@ -10,14 +10,11 @@ Highlights in Rails 4.2: These release notes cover only the major changes. To learn about various bug fixes and changes, please refer to the change logs or check out the [list of -commits](https://github.com/rails/rails/commits/master) in the main Rails +commits](https://github.com/rails/rails/commits/4-2-stable) in the main Rails repository on GitHub. -------------------------------------------------------------------------------- -NOTE: This document is a work in progress, please help to improve this by sending -a [pull request](https://github.com/rails/rails/edit/master/guides/source/4_2_release_notes.md). - Upgrading to Rails 4.2 ---------------------- @@ -54,26 +51,26 @@ then deserialized again at run time. ### Adequate Record -Adequate Record is a set of refactorings that make Active Record `find` and -`find_by` methods and some association queries up to 2x faster. +Adequate Record is a set of performance improvements in Active Record that makes +common `find` and `find_by` calls and some association queries up to 2x faster. -It works by caching SQL query patterns while executing the Active Record calls. -The cache helps skip parts of the computation involved in the transformation of -the calls into SQL queries. More details in [Aaron Patterson's -post](http://tenderlovemaking.com/2014/02/19/adequaterecord-pro-like-activerecord.html). +It works by caching common SQL queries as prepared statements and reusing them +on similar calls, skipping most of the query-generation work on subsequent +calls. For more details, please refer to [Aaron Patterson's blog post](http://tenderlovemaking.com/2014/02/19/adequaterecord-pro-like-activerecord.html). -Nothing special has to be done to activate this feature. Most `find` and -`find_by` calls and association queries will use it automatically. Examples: +Active Record will automatically take advantage of this feature on the supported +operations without any user involvement and code changes. Here are some examples +of the supported operations: ```ruby -Post.find 1 # caches query pattern -Post.find 2 # uses the cached pattern +Post.find 1 # First call will generate and cache the prepared statement +Post.find 2 # Second call will reuse the cached statement -Post.find_by_title 'first post' # caches query pattern -Post.find_by_title 'second post' # uses the cached pattern +Post.find_by_title 'first post' +Post.find_by_title 'second post' -post.comments # caches query pattern -post.comments(true) # uses cached pattern +post.comments +post.comments(true) ``` The caching is not used in the following scenarios: @@ -100,8 +97,8 @@ New applications generated from Rails 4.2 now come with the Web Console gem by default. Web Console is a set of debugging tools for your Rails application. It will add -an interactive console on every error page, a `console` view helper and a VT100 -compatible terminal. +an interactive console on every error page and a `console` view and controller +helper. The interactive console on the error pages let you execute code where the exception originated. It's quite handy being able to introspect the state that @@ -110,9 +107,8 @@ led to the error. The `console` view helper launches an interactive console within the context of the view where it is invoked. -Finally, you can launch a VT100 terminal that runs `rails console`. If you need -to create or modify existing test data, you can do that straight from the -browser. +The `console` controller helper spawns an interactive console within the +context of the controller action it was invoked in. ### Foreign key support @@ -206,22 +202,6 @@ to start the server with `rails server -b 0.0.0.0` to restore the old behavior. If you do this, be sure to configure your firewall properly such that only trusted machines on your network can access your development server. -### Production logging - -The default log level in the `production` environment is now `:debug`. This -makes it consistent with the other environments, and ensures plenty of -information is available to diagnose problems. - -It can be returned to the previous level, `:info`, in the environment -configuration: - -```ruby -# config/environments/production.rb - -# Decrease the log volume. -config.log_level = :info -``` - ### HTML Sanitizer The HTML sanitizer has been replaced with a new, more robust, implementation @@ -244,10 +224,9 @@ for more detail on the changes in the new sanitizer. ### `assert_select` -`assert_select` is now based on Nokogiri, making it (TODO: betterer). - -As a result, some previously-valid selectors are now unsupported. If your -application is using any of these spellings, you will need to update them: +`assert_select` is now based on Nokogiri. As a result, some previously-valid +selectors are now unsupported. If your application is using any of these +spellings, you will need to update them: * Values in attribute selectors may need to be quoted if they contain non-alphanumeric characters. @@ -308,6 +287,16 @@ Please refer to the [Changelog][railties] for detailed changes. ### Deprecations +* Deprecated missing `config.log_level` for production environments. + ([Pull Request](https://github.com/rails/rails/pull/16622)) + +* Deprecated `rake test:all` in favor of `rake test` as it now run all tests + in the `test` folder. + ([Pull Request](https://github.com/rails/rails/pull/17348)) + +* Deprecated `rake test:all:db` in favor of `rake test:db`. + ([Pull Request](https://github.com/rails/rails/pull/17348)) + * Deprecated `Rails::Rack::LogTailer` without replacement. ([Commit](https://github.com/rails/rails/commit/84a13e019e93efaa8994b3f8303d635a7702dbce)) @@ -319,9 +308,6 @@ Please refer to the [Changelog][railties] for detailed changes. * Added a `required` option to the model generator for associations. ([Pull Request](https://github.com/rails/rails/pull/16062)) -* Introduced an `after_bundle` callback for use in Rails templates. - ([Pull Request](https://github.com/rails/rails/pull/16359)) - * Introduced the `x` namespace for defining custom configuration options: ```ruby @@ -375,6 +361,9 @@ Please refer to the [Changelog][railties] for detailed changes. * Introduced an API to register new extensions for `rake notes`. ([Pull Request](https://github.com/rails/rails/pull/14379)) +* Introduced an `after_bundle` callback for use in Rails templates. + ([Pull Request](https://github.com/rails/rails/pull/16359)) + * Introduced `Rails.gem_version` as a convenience method to return `Gem::Version.new(Rails.version)`. ([Pull Request](https://github.com/rails/rails/pull/14101)) @@ -390,7 +379,8 @@ Please refer to the [Changelog][action-pack] for detailed changes. * `respond_with` and the class-level `respond_to` were removed from Rails and moved to the `responders` gem (version 2.0). Add `gem 'responders', '~> 2.0'` to your `Gemfile` to continue using these features. - ([Pull Request](https://github.com/rails/rails/pull/16526)) + ([Pull Request](https://github.com/rails/rails/pull/16526), + [More Details](http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#responders)) * Removed deprecated `AbstractController::Helpers::ClassMethods::MissingHelperError` in favor of `AbstractController::Helpers::MissingHelperError`. @@ -423,8 +413,6 @@ Please refer to the [Changelog][action-pack] for detailed changes. # bad Rails.application.routes.url_helpers.root_path('controller' => 'posts', 'action' => 'index') # good - Rails.application.routes.url_helpers.root_path(:controller => 'posts', :action => 'index') - # better :trollface: Rails.application.routes.url_helpers.root_path(controller: 'posts', action: 'index') ``` @@ -432,18 +420,6 @@ Please refer to the [Changelog][action-pack] for detailed changes. ### Notable changes -* Rails will now automatically include the template's digest in ETags. - ([Pull Request](https://github.com/rails/rails/pull/16527)) - -* `render nothing: true` or rendering a `nil` body no longer add a single - space padding to the response body. - ([Pull Request](https://github.com/rails/rails/pull/14883)) - -* Introduced the `always_permitted_parameters` option to configure which - parameters are permitted globally. The default value of this configuration - is `['controller', 'action']`. - ([Pull Request](https://github.com/rails/rails/pull/15933)) - * The `*_filter` family methods have been removed from the documentation. Their usage is discouraged in favor of the `*_action` family methods: @@ -470,6 +446,22 @@ Please refer to the [Changelog][action-pack] for detailed changes. (Commit [1](https://github.com/rails/rails/commit/6c5f43bab8206747a8591435b2aa0ff7051ad3de), [2](https://github.com/rails/rails/commit/489a8f2a44dc9cea09154ee1ee2557d1f037c7d4)) +* `render nothing: true` or rendering a `nil` body no longer add a single + space padding to the response body. + ([Pull Request](https://github.com/rails/rails/pull/14883)) + +* Rails will now automatically include the template's digest in ETags. + ([Pull Request](https://github.com/rails/rails/pull/16527)) + +* Segments that are passed into URL helpers are now automatically escaped. + ([Commit](https://github.com/rails/rails/commit/5460591f0226a9d248b7b4f89186bd5553e7768f)) + + +* Introduced the `always_permitted_parameters` option to configure which + parameters are permitted globally. The default value of this configuration + is `['controller', 'action']`. + ([Pull Request](https://github.com/rails/rails/pull/15933)) + * Added HTTP method `MKCALENDAR` from RFC-4791 ([Pull Request](https://github.com/rails/rails/pull/15121)) @@ -477,9 +469,6 @@ Please refer to the [Changelog][action-pack] for detailed changes. and action name in the payload. ([Pull Request](https://github.com/rails/rails/pull/14137)) -* Segments that are passed into URL helpers are now automatically escaped. - ([Commit](https://github.com/rails/rails/commit/5460591f0226a9d248b7b4f89186bd5553e7768f)) - * Improved the Routing Error page with fuzzy matching for route search. ([Pull Request](https://github.com/rails/rails/pull/14619)) @@ -494,19 +483,6 @@ Please refer to the [Changelog][action-pack] for detailed changes. serving assets from your Rails server in production. ([Pull Request](https://github.com/rails/rails/pull/16466)) -* The way `assert_select` works has changed; specifically a different library - is used to interpret CSS selectors, build the transient DOM that the - selectors are applied against, and to extract the data from that DOM. These - changes should only affect edge cases. Examples: - * Values in attribute selectors may need to be quoted if they contain - non-alphanumeric characters. - * DOMs built from HTML source containing invalid HTML with improperly - nested elements may differ. - * If the data selected contains entities, the value selected for comparison - used to be raw (e.g. `AT&T`), and now is evaluated - (e.g. `AT&T`). - - Action View ------------- @@ -529,16 +505,16 @@ Please refer to the [Changelog][action-view] for detailed changes. `render file: "foo/bar"`. ([Pull Request](https://github.com/rails/rails/pull/16888)) +* The form helpers no longer generate a `<div>` element with inline CSS around + the hidden fields. + ([Pull Request](https://github.com/rails/rails/pull/14738)) + * Introduced a `#{partial_name}_iteration` special local variable for use with partials that are rendered with a collection. It provides access to the current state of the iteration via the `#index`, `#size`, `#first?` and `#last?` methods. ([Pull Request](https://github.com/rails/rails/pull/7698)) -* The form helpers no longer generate a `<div>` element with inline CSS around - the hidden fields. - ([Pull Request](https://github.com/rails/rails/pull/14738)) - * Placeholder I18n follows the same convention as `label` I18n. ([Pull Request](https://github.com/rails/rails/pull/16438)) @@ -591,39 +567,15 @@ Please refer to the [Changelog][active-record] for detailed changes. ### Deprecations -* Deprecated `sanitize_sql_hash_for_conditions` without replacement. Using a - `Relation` for performing queries and updates is the prefered API. - ([Commit](https://github.com/rails/rails/commit/d5902c9e)) - * Deprecated swallowing of errors inside `after_commit` and `after_rollback`. ([Pull Request](https://github.com/rails/rails/pull/16537)) -* Deprecated calling `DatabaseTasks.load_schema` without a connection. Use - `DatabaseTasks.load_schema_current` instead. - ([Commit](https://github.com/rails/rails/commit/f15cef67f75e4b52fd45655d7c6ab6b35623c608)) - -* Deprecated `Reflection#source_macro` without replacement as it is no longer - needed in Active Record. - ([Pull Request](https://github.com/rails/rails/pull/16373)) - * Deprecated broken support for automatic detection of counter caches on `has_many :through` associations. You should instead manually specify the counter cache on the `has_many` and `belongs_to` associations for the through records. ([Pull Request](https://github.com/rails/rails/pull/15754)) -* Deprecated `serialized_attributes` without replacement. - ([Pull Request](https://github.com/rails/rails/pull/15704)) - -* Deprecated returning `nil` from `column_for_attribute` when no column - exists. It will return a null object in Rails 5.0. - ([Pull Request](https://github.com/rails/rails/pull/15878)) - -* Deprecated using `.joins`, `.preload` and `.eager_load` with associations - that depends on the instance state (i.e. those defined with a scope that - takes an argument) without replacement. - ([Commit](https://github.com/rails/rails/commit/ed56e596a0467390011bc9d56d462539776adac1)) - * Deprecated passing Active Record objects to `.find` or `.exists?`. Call `#id` on the objects first. (Commit [1](https://github.com/rails/rails/commit/d92ae6ccca3bcfd73546d612efaea011270bd270), @@ -641,34 +593,35 @@ Please refer to the [Changelog][active-record] for detailed changes. ([Commit](https://github.com/rails/rails/commit/91949e48cf41af9f3e4ffba3e5eecf9b0a08bfc3)) -### Notable changes +* Deprecated calling `DatabaseTasks.load_schema` without a connection. Use + `DatabaseTasks.load_schema_current` instead. + ([Commit](https://github.com/rails/rails/commit/f15cef67f75e4b52fd45655d7c6ab6b35623c608)) -* `ActiveRecord::Base#reflections` now returns a hash with `String` keys instead of `Symbol` keys. - ([Pull Request](https://github.com/rails/rails/pull/17718)) +* Deprecated `sanitize_sql_hash_for_conditions` without replacement. Using a + `Relation` for performing queries and updates is the prefered API. + ([Commit](https://github.com/rails/rails/commit/d5902c9e)) -* The PostgreSQL adapter now supports the `JSONB` datatype in PostgreSQL 9.4+. - ([Pull Request](https://github.com/rails/rails/pull/16220)) +* Deprecated `Reflection#source_macro` without replacement as it is no longer + needed in Active Record. + ([Pull Request](https://github.com/rails/rails/pull/16373)) -* The `#references` method in migrations now supports a `type` option for - specifying the type of the foreign key (e.g. `:uuid`). - ([Pull Request](https://github.com/rails/rails/pull/16231)) +* Deprecated `serialized_attributes` without replacement. + ([Pull Request](https://github.com/rails/rails/pull/15704)) -* Added a `:required` option to singular associations, which defines a - presence validation on the association. - ([Pull Request](https://github.com/rails/rails/pull/16056)) +* Deprecated returning `nil` from `column_for_attribute` when no column + exists. It will return a null object in Rails 5.0. + ([Pull Request](https://github.com/rails/rails/pull/15878)) -* Introduced `ActiveRecord::Base#validate!` that raises `RecordInvalid` if the - record is invalid. - ([Pull Request](https://github.com/rails/rails/pull/8639)) +* Deprecated using `.joins`, `.preload` and `.eager_load` with associations + that depends on the instance state (i.e. those defined with a scope that + takes an argument) without replacement. + ([Commit](https://github.com/rails/rails/commit/ed56e596a0467390011bc9d56d462539776adac1)) -* `ActiveRecord::Base#reload` now behaves the same as `m = Model.find(m.id)`, - meaning that it no longer retains the extra attributes from custom - `select`s. - ([Pull Request](https://github.com/rails/rails/pull/15866)) +### Notable changes -* Introduced the `bin/rake db:purge` task to empty the database for the - current environment. - ([Commit](https://github.com/rails/rails/commit/e2f232aba15937a4b9d14bd91e0392c6d55be58d)) +* Added a `:required` option to singular associations, which defines a + presence validation on the association. + ([Pull Request](https://github.com/rails/rails/pull/16056)) * `ActiveRecord::Dirty` now detects in-place changes to mutable values. Serialized attributes on Active Record models will no longer save when @@ -678,35 +631,57 @@ Please refer to the [Changelog][active-record] for detailed changes. [2](https://github.com/rails/rails/pull/15786), [3](https://github.com/rails/rails/pull/15788)) -* Added support for `#pretty_print` in `ActiveRecord::Base` objects. - ([Pull Request](https://github.com/rails/rails/pull/15172)) +* Introduced the `bin/rake db:purge` task to empty the database for the + current environment. + ([Commit](https://github.com/rails/rails/commit/e2f232aba15937a4b9d14bd91e0392c6d55be58d)) + +* Introduced `ActiveRecord::Base#validate!` that raises `RecordInvalid` if the + record is invalid. + ([Pull Request](https://github.com/rails/rails/pull/8639)) + +* Introduced `#validate` as an alias for `#valid?`. + ([Pull Request](https://github.com/rails/rails/pull/14456)) + +* `#touch` now accepts multiple attributes to be touched at once. + ([Pull Request](https://github.com/rails/rails/pull/14423)) + +* The PostgreSQL adapter now supports the `JSONB` datatype in PostgreSQL 9.4+. + ([Pull Request](https://github.com/rails/rails/pull/16220)) * PostgreSQL and SQLite adapters no longer add a default limit of 255 characters on string columns. ([Pull Request](https://github.com/rails/rails/pull/14579)) +* Added support for the `citext` column type in PostgreSQL adapter. + ([Pull Request](https://github.com/rails/rails/pull/12523)) + +* Added support for user-created range types in PostgreSQL adapter. + ([Commit](https://github.com/rails/rails/commit/4cb47167e747e8f9dc12b0ddaf82bdb68c03e032)) + * `sqlite3:///some/path` now resolves to the absolute system path `/some/path`. For relative paths, use `sqlite3:some/path` instead. (Previously, `sqlite3:///some/path` resolved to the relative path `some/path`. This behaviour was deprecated on Rails 4.1). ([Pull Request](https://github.com/rails/rails/pull/14569)) -* Introduced `#validate` as an alias for `#valid?`. - ([Pull Request](https://github.com/rails/rails/pull/14456)) - -* `#touch` now accepts multiple attributes to be touched at once. - ([Pull Request](https://github.com/rails/rails/pull/14423)) - * Added support for fractional seconds for MySQL 5.6 and above. (Pull Request [1](https://github.com/rails/rails/pull/8240), [2](https://github.com/rails/rails/pull/14359)) -* Added support for the `citext` column type in PostgreSQL adapter. - ([Pull Request](https://github.com/rails/rails/pull/12523)) +* Added support for `#pretty_print` in `ActiveRecord::Base` objects. + ([Pull Request](https://github.com/rails/rails/pull/15172)) -* Added support for user-created range types in PostgreSQL adapter. - ([Commit](https://github.com/rails/rails/commit/4cb47167e747e8f9dc12b0ddaf82bdb68c03e032)) +* `ActiveRecord::Base#reload` now behaves the same as `m = Model.find(m.id)`, + meaning that it no longer retains the extra attributes from custom + `select`s. + ([Pull Request](https://github.com/rails/rails/pull/15866)) + +* `ActiveRecord::Base#reflections` now returns a hash with `String` keys instead of `Symbol` keys. + ([Pull Request](https://github.com/rails/rails/pull/17718)) +* The `#references` method in migrations now supports a `type` option for + specifying the type of the foreign key (e.g. `:uuid`). + ([Pull Request](https://github.com/rails/rails/pull/16231)) Active Model ------------ @@ -729,6 +704,9 @@ Please refer to the [Changelog][active-model] for detailed changes. ### Notable changes +* Introduced `#validate` as an alias for `#valid?`. + ([Pull Request](https://github.com/rails/rails/pull/14456)) + * Introduced the `restore_attributes` method in `ActiveModel::Dirty` to restore the changed (dirty) attributes to their previous values. (Pull Request [1](https://github.com/rails/rails/pull/14861), @@ -742,10 +720,6 @@ Please refer to the [Changelog][active-model] for detailed changes. characters if validations are enabled. ([Pull Request](https://github.com/rails/rails/pull/15708)) -* Introduced `#validate` as an alias for `#valid?`. - ([Pull Request](https://github.com/rails/rails/pull/14456)) - - Active Support -------------- diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 4c98d3e1d5..1b838201cc 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -171,7 +171,6 @@ name: Ruby on Rails 4.2 Release Notes url: 4_2_release_notes.html description: Release notes for Rails 4.2. - work_in_progress: true - name: Ruby on Rails 4.1 Release Notes url: 4_1_release_notes.html diff --git a/guides/source/engines.md b/guides/source/engines.md index de33f5f067..a1f2da18ed 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -1166,7 +1166,7 @@ end Using `Class#class_eval` is great for simple adjustments, but for more complex class modifications, you might want to consider using [`ActiveSupport::Concern`] -(http://edgeapi.rubyonrails.org/classes/ActiveSupport/Concern.html). +(http://api.rubyonrails.org/classes/ActiveSupport/Concern.html). ActiveSupport::Concern manages load order of interlinked dependent modules and classes at run time allowing you to significantly modularize your code. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 042ff76212..4ce61c282d 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -50,21 +50,9 @@ Don't forget to review the difference, to see if there were any unexpected chang Upgrading from Rails 4.1 to Rails 4.2 ------------------------------------- -NOTE: This section is a work in progress, please help to improve this by sending -a [pull request](https://github.com/rails/rails/edit/master/guides/source/upgrading_ruby_on_rails.md). - ### Web Console -First, add `gem 'web-console', '~> 2.0.0.beta4'` to the `:development` group in your Gemfile and run `bundle install` (it won't have been included when you upgraded Rails). Once it's been installed, you can simply drop a reference to the console helper (i.e., `<%= console %>`) into any view you want to enable it for. A console will also be provided on any error page you view in your development environment. - -Additionally, you can tell Rails to automatically mount a VT100-compatible console on a predetermined path by setting the appropriate configuration flags in your development config: - -```ruby -# config/environments/development.rb - -config.web_console.automount = true -config.web_console.default_mount_path = '/terminal' # Optional, defaults to /console -``` +First, add `gem 'web-console', '~> 2.0'` to the `:development` group in your Gemfile and run `bundle install` (it won't have been included when you upgraded Rails). Once it's been installed, you can simply drop a reference to the console helper (i.e., `<%= console %>`) into any view you want to enable it for. A console will also be provided on any error page you view in your development environment. ### Responders @@ -145,6 +133,18 @@ assigning `nil` to a serialized attribute will save it to the database as `NULL` instead of passing the `nil` value through the coder (e.g. `"null"` when using the `JSON` coder). +### Production log level + +In Rails 5, the default log level for the production environment will be changed +to `:debug` (from `:info`). To preserve the current default, add the following +line to your `production.rb`: + +```ruby +# Set to `:info` to match the current default, or set to `:debug` to opt-into +# the future default. +config.log_level = :info +``` + ### `after_bundle` in Rails templates If you have a Rails template that adds all the files in version control, it diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index a1c7587f4d..ff6dcac465 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,12 @@ +* Generated migrations add the appropriate foreign key constraints to + references. + + *Derek Prior* + +* Deprecate different default for `log_level` in production. + + *Godfrey Chan*, *Matthew Draper* + * Generated `.gitignore` excludes the whole `log/` directory, not only `*.log` files. diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index cb0936d1ef..9014560611 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -44,7 +44,7 @@ module Rails find_cmd_and_exec(['mysql', 'mysql5'], *args) - when /postgres|postgis/ + when /^postgres|^postgis/ ENV['PGUSER'] = config["username"] if config["username"] ENV['PGHOST'] = config["host"] if config["host"] ENV['PGPORT'] = config["port"].to_s if config["port"] @@ -74,6 +74,21 @@ module Rails find_cmd_and_exec('sqlplus', logon) + when "sqlserver" + args = [] + + args += ["-D", "#{config['database']}"] if config['database'] + args += ["-U", "#{config['username']}"] if config['username'] + args += ["-P", "#{config['password']}"] if config['password'] + + if config['host'] + host_arg = "#{config['host']}" + host_arg << ":#{config['port']}" if config['port'] + args += ["-S", host_arg] + end + + find_cmd_and_exec("sqsh", *args) + else abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!" end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 023ea98145..4b7da32208 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -351,7 +351,7 @@ module Rails base.called_from = begin call_stack = if Kernel.respond_to?(:caller_locations) - caller_locations.map(&:path) + caller_locations.map(&:absolute_path) else # Remove the line number from backtraces making sure we don't leave anything behind caller.map { |p| p.sub(/:\d+.*/, '') } diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index ec32bb8efc..0823b0cc46 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -195,11 +195,9 @@ module Rails def rails_gemfile_entry if options.dev? - [GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH), - GemfileEntry.github('rails-dom-testing', 'rails/rails-dom-testing')] + [GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH)] elsif options.edge? - [GemfileEntry.github('rails', 'rails/rails'), - GemfileEntry.github('rails-dom-testing', 'rails/rails-dom-testing')] + [GemfileEntry.github('rails', 'rails/rails')] else [GemfileEntry.version('rails', Rails::VERSION::STRING, @@ -278,14 +276,8 @@ module Rails [] else gems = [coffee_gemfile_entry, javascript_runtime_gemfile_entry] - - if options[:javascript] == 'jquery' - gems << GemfileEntry.version('jquery-rails', '~> 4.0.0.beta2', - 'Use jQuery as the JavaScript library') - else - gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, - "Use #{options[:javascript]} as the JavaScript library") - end + gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, + "Use #{options[:javascript]} as the JavaScript library") unless options[:skip_turbolinks] gems << GemfileEntry.version("turbolinks", nil, diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 5961f7515c..7027312aa9 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -32,7 +32,7 @@ group :development, :test do <%- end -%> # Access an IRB console on exception pages or by using <%%= console %> in views - gem 'web-console', '~> 2.0.0.beta4' + gem 'web-console', '~> 2.0' <%- if spring_install? %> # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 391139d7f8..1f97807f8c 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -967,6 +967,36 @@ module ApplicationTests end end + test "Blank config.log_level is not deprecated for non-production environment" do + with_rails_env "development" do + assert_not_deprecated do + make_basic_app do |app| + app.config.log_level = nil + end + end + end + end + + test "Blank config.log_level is deprecated for the production environment" do + with_rails_env "production" do + assert_deprecated(/log_level/) do + make_basic_app do |app| + app.config.log_level = nil + end + end + end + end + + test "Not blank config.log_level is not deprecated for the production environment" do + with_rails_env "production" do + assert_not_deprecated do + make_basic_app do |app| + app.config.log_level = :info + end + end + end + end + test "config.log_level with custom logger" do make_basic_app do |app| app.config.logger = Logger.new(STDOUT) diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 524c70aad2..0a5873bcbf 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -175,15 +175,6 @@ module ApplicationTests db_test_load_structure end - test 'db:test deprecation' do - require "#{app_path}/config/environment" - Dir.chdir(app_path) do - output = `bundle exec rake db:migrate db:test:prepare 2>&1` - assert_equal "WARNING: db:test:prepare is deprecated. The Rails test helper now maintains " \ - "your test schema automatically, see the release notes for details.\n", output - end - end - test 'db:setup loads schema and seeds database' do begin @old_rails_env = ENV["RAILS_ENV"] diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index c724c867ec..c7132837b1 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -193,6 +193,98 @@ module ApplicationTests assert_successful_test_run('models/user_test.rb') end + # TODO: would be nice if we could detect the schema change automatically. + # For now, the user has to synchronize the schema manually. + # This test-case serves as a reminder for this use-case. + test "manually synchronize test schema after rollback" do + output = script('generate model user name:string') + version = output.match(/(\d+)_create_users\.rb/)[1] + + app_file 'test/models/user_test.rb', <<-RUBY + require 'test_helper' + + class UserTest < ActiveSupport::TestCase + test "user" do + assert_equal ["id", "name"], User.columns_hash.keys + end + end + RUBY + app_file 'db/schema.rb', <<-RUBY + ActiveRecord::Schema.define(version: #{version}) do + create_table :users do |t| + t.string :name + end + end + RUBY + + assert_successful_test_run "models/user_test.rb" + + # Simulate `db:rollback` + edit of the migration file + `db:migrate` + app_file 'db/schema.rb', <<-RUBY + ActiveRecord::Schema.define(version: #{version}) do + create_table :users do |t| + t.string :name + t.integer :age + end + end + RUBY + + assert_successful_test_run "models/user_test.rb" + + Dir.chdir(app_path) { `bin/rake db:test:prepare` } + + assert_unsuccessful_run "models/user_test.rb", <<-ASSERTION +Expected: ["id", "name"] + Actual: ["id", "name", "age"] + ASSERTION + end + + test "hooks for plugins" do + output = script('generate model user name:string') + version = output.match(/(\d+)_create_users\.rb/)[1] + + app_file 'lib/tasks/hooks.rake', <<-RUBY + task :before_hook do + has_user_table = ActiveRecord::Base.connection.table_exists?('users') + puts "before: " + has_user_table.to_s + end + + task :after_hook do + has_user_table = ActiveRecord::Base.connection.table_exists?('users') + puts "after: " + has_user_table.to_s + end + + Rake::Task["db:test:prepare"].enhance [:before_hook] do + Rake::Task[:after_hook].invoke + end + RUBY + app_file 'test/models/user_test.rb', <<-RUBY + require 'test_helper' + class UserTest < ActiveSupport::TestCase + test "user" do + User.create! name: "Jon" + end + end + RUBY + + # Simulate `db:migrate` + app_file 'db/schema.rb', <<-RUBY + ActiveRecord::Schema.define(version: #{version}) do + create_table :users do |t| + t.string :name + end + end + RUBY + + output = assert_successful_test_run "models/user_test.rb" + assert_includes output, "before: false\nafter: true" + + # running tests again won't trigger a schema update + output = assert_successful_test_run "models/user_test.rb" + assert_not_includes output, "before:" + assert_not_includes output, "after:" + end + private def assert_unsuccessful_run(name, message) result = run_test_file(name) @@ -208,7 +300,7 @@ module ApplicationTests end def run_test_file(name, options = {}) - ruby '-Itest', "#{app_path}/test/#{name}", options + ruby '-Itest', "#{app_path}/test/#{name}", options.deep_merge(env: {"RAILS_ENV" => "test"}) end def ruby(*args) diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index 72f5fe29ca..c2c8e2abad 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -85,6 +85,18 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_remove_migration_with_references_removes_foreign_keys + migration = "remove_references_from_books" + run_generator [migration, "author:belongs_to", "distributor:references{polymorphic}"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/remove_foreign_key :books, :authors/, change) + assert_no_match(/remove_foreign_key :books, :distributors/, change) + end + end + end + def test_add_migration_with_attributes_and_indices migration = "add_title_with_index_and_body_to_posts" run_generator [migration, "title:string:index", "body:text", "user_id:integer:uniq"] @@ -171,6 +183,18 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_add_migration_with_references_adds_foreign_keys + migration = "add_references_to_books" + run_generator [migration, "author:belongs_to", "distributor:references{polymorphic}"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/add_foreign_key :books, :authors/, change) + assert_no_match(/add_foreign_key :books, :distributors/, change) + end + end + end + def test_create_join_table_migration migration = "add_media_join_table" run_generator [migration, "artist_id", "musics:uniq"] @@ -205,7 +229,7 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end end - + def test_properly_identifies_usage_file assert generator_class.send(:usage_path) end diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index c78597c81b..ac7a0acf6b 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -407,6 +407,27 @@ class ModelGeneratorTest < Rails::Generators::TestCase end end + def test_foreign_key_is_added_for_references + run_generator ["account", "supplier:belongs_to", "user:references"] + + assert_migration "db/migrate/create_accounts.rb" do |m| + assert_method :change, m do |up| + assert_match(/add_foreign_key :accounts, :suppliers/, up) + assert_match(/add_foreign_key :accounts, :users/, up) + end + end + end + + def test_foreign_key_is_skipped_for_polymorphic_references + run_generator ["account", "supplier:belongs_to{polymorphic}"] + + assert_migration "db/migrate/create_accounts.rb" do |m| + assert_method :change, m do |up| + assert_no_match(/add_foreign_key :accounts, :suppliers/, up) + end + end + end + private def assert_generated_fixture(path, parsed_contents) fixture_file = File.new File.expand_path(path, destination_root) diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index bf2992005b..9ad0ec0d34 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -143,6 +143,7 @@ module TestHelpers config.active_support.deprecation = :log config.active_support.test_order = :random config.action_controller.allow_forgery_protection = false + config.log_level = :info RUBY end @@ -162,6 +163,8 @@ module TestHelpers app.secrets.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" app.config.session_store :cookie_store, key: "_myapp_session" app.config.active_support.deprecation = :log + app.config.active_support.test_order = :random + app.config.log_level = :info yield app if block_given? app.initialize! |