diff options
22 files changed, 252 insertions, 101 deletions
diff --git a/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb b/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb index f23e575fe5..00fb9bd48f 100644 --- a/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb +++ b/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb @@ -1,4 +1,4 @@ -<% module_namespacing do %> +<% module_namespacing do -%> class ApplicationMailer < ActionMailer::Base default from: 'from@example.com' layout 'mailer' diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 910cca2f49..79297ac119 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -136,7 +136,7 @@ module ActiveModel # * <tt>:too_long</tt> - The error message if the attribute goes over the # maximum (default is: "is too long (maximum is %{count} characters)"). # * <tt>:too_short</tt> - The error message if the attribute goes under the - # minimum (default is: "is too short (min is %{count} characters)"). + # minimum (default is: "is too short (minimum is %{count} characters)"). # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> # method and the attribute is the wrong size (default is: "is the wrong # length (should be %{count} characters)"). diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index d59101d621..e92f68eaa0 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1441,11 +1441,6 @@ *Hyonjee Joo* -* Deprecate passing of `start` value to `find_in_batches` and `find_each` - in favour of `begin_at` value. - - *Vipul A M* - * Add `foreign_key_exists?` method. *Tõnis Simo* 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 fe58fce313..42d3c68970 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -34,8 +34,6 @@ module ActiveRecord class_attribute :emulate_booleans self.emulate_booleans = true - QUOTED_TRUE, QUOTED_FALSE = '1', '0' - NATIVE_DATABASE_TYPES = { primary_key: "int auto_increment PRIMARY KEY", string: { name: "varchar", limit: 255 }, @@ -164,34 +162,6 @@ module ActiveRecord raise NotImplementedError end - #-- - # QUOTING ================================================== - #++ - - def quoted_true - QUOTED_TRUE - end - - def unquoted_true - 1 - end - - def quoted_false - QUOTED_FALSE - end - - def unquoted_false - 0 - end - - def quoted_date(value) - if supports_datetime_with_precision? - super - else - super.sub(/\.\d{6}\z/, '') - end - end - # REFERENTIAL INTEGRITY ==================================== def disable_referential_integrity #:nodoc: @@ -571,8 +541,7 @@ module ActiveRecord # SHOW VARIABLES LIKE 'name' def show_variable(name) - variables = select_all("select @@#{name} as 'Value'", 'SCHEMA') - variables.first['Value'] unless variables.empty? + select_value("SELECT @@#{name}", 'SCHEMA') rescue ActiveRecord::StatementInvalid nil end @@ -939,8 +908,8 @@ module ActiveRecord class MysqlString < Type::String # :nodoc: def serialize(value) case value - when true then QUOTED_TRUE - when false then QUOTED_FALSE + when true then MySQL::Quoting::QUOTED_TRUE + when false then MySQL::Quoting::QUOTED_FALSE else super end end @@ -949,8 +918,8 @@ module ActiveRecord def cast_value(value) case value - when true then QUOTED_TRUE - when false then QUOTED_FALSE + when true then MySQL::Quoting::QUOTED_TRUE + when false then MySQL::Quoting::QUOTED_FALSE else super end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb index 7c5980da2a..fbab654112 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb @@ -2,6 +2,8 @@ module ActiveRecord module ConnectionAdapters module MySQL module Quoting # :nodoc: + QUOTED_TRUE, QUOTED_FALSE = '1', '0' + def quote_column_name(name) @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`" end @@ -10,6 +12,30 @@ module ActiveRecord @quoted_table_names[name] ||= super.gsub('.', '`.`') end + def quoted_true + QUOTED_TRUE + end + + def unquoted_true + 1 + end + + def quoted_false + QUOTED_FALSE + end + + def unquoted_false + 0 + end + + def quoted_date(value) + if supports_datetime_with_precision? + super + else + super.sub(/\.\d{6}\z/, '') + end + end + private def _quote(value) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb index faf2f375dc..d3a91f73c8 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb @@ -2,6 +2,14 @@ module ActiveRecord module ConnectionAdapters module SQLite3 module Quoting # :nodoc: + def quote_string(s) + @connection.class.quote(s) + end + + def quote_table_name_for_assignment(table, attr) + quote_column_name(attr) + end + def quote_column_name(name) @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}") end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 5c8e428bef..786b0ab2ed 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -176,16 +176,6 @@ module ActiveRecord true end - # QUOTING ================================================== - - def quote_string(s) #:nodoc: - @connection.class.quote(s) - end - - def quote_table_name_for_assignment(table, attr) - quote_column_name(attr) - end - #-- # DATABASE STATEMENTS ====================================== #++ diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index f451ed1764..bbbc824b25 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -23,23 +23,27 @@ module ActiveRecord end end - def self.install_executor_hooks(executor = ActiveSupport::Executor) - executor.to_run do - connection = ActiveRecord::Base.connection - enabled = connection.query_cache_enabled - connection_id = ActiveRecord::Base.connection_id - connection.enable_query_cache! + def self.run + connection = ActiveRecord::Base.connection + enabled = connection.query_cache_enabled + connection_id = ActiveRecord::Base.connection_id + connection.enable_query_cache! - @restore_query_cache_settings = lambda do - ActiveRecord::Base.connection_id = connection_id - ActiveRecord::Base.connection.clear_query_cache - ActiveRecord::Base.connection.disable_query_cache! unless enabled - end - end + [enabled, connection_id] + end - executor.to_complete do - @restore_query_cache_settings.call if defined?(@restore_query_cache_settings) + def self.complete(state) + enabled, connection_id = state + ActiveRecord::Base.connection_id = connection_id + ActiveRecord::Base.connection.clear_query_cache + ActiveRecord::Base.connection.disable_query_cache! unless enabled + end + + def self.install_executor_hooks(executor = ActiveSupport::Executor) + executor.register_hook(self) + + executor.to_complete do # FIXME: This should be skipped when env['rack.test'] ActiveRecord::Base.clear_active_connections! end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 00cf8536e1..b1b169ae2f 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -256,7 +256,7 @@ db_namespace = namespace :db do end desc 'Loads a schema.rb file into the database' - task :load => [:environment, :load_config] do + task :load => [:environment, :load_config, :check_protected_environments] do ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA']) end diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb index 2bd1c01d35..00c5745a25 100644 --- a/activesupport/lib/active_support/execution_wrapper.rb +++ b/activesupport/lib/active_support/execution_wrapper.rb @@ -19,6 +19,32 @@ module ActiveSupport set_callback(:complete, *args, &block) end + # Register an object to be invoked during both the +run+ and + # +complete+ steps. + # + # +hook.complete+ will be passed the value returned from +hook.run+, + # and will only be invoked if +run+ has previously been called. + # (Mostly, this means it won't be invoked if an exception occurs in + # a preceding +to_run+ block; all ordinary +to_complete+ blocks are + # invoked in that situation.) + def self.register_hook(hook, outer: false) + if outer + run_args = [prepend: true] + complete_args = [:after] + else + run_args = complete_args = [] + end + + to_run(*run_args) do + hook_state[hook] = hook.run + end + to_complete(*complete_args) do + if hook_state.key?(hook) + hook.complete hook_state[hook] + end + end + end + # Run this execution. # # Returns an instance, whose +complete!+ method *must* be invoked @@ -29,7 +55,15 @@ module ActiveSupport if active? Null else - new.tap(&:run!) + new.tap do |instance| + success = nil + begin + instance.run! + success = true + ensure + instance.complete! unless success + end + end end end @@ -37,11 +71,11 @@ module ActiveSupport def self.wrap return yield if active? - state = run! + instance = run! begin yield ensure - state.complete! + instance.complete! end end @@ -74,5 +108,10 @@ module ActiveSupport ensure self.class.active.delete Thread.current end + + private + def hook_state + @_hook_state ||= {} + end end end diff --git a/activesupport/lib/active_support/reloader.rb b/activesupport/lib/active_support/reloader.rb index 5d1f0e1e66..5623bdd349 100644 --- a/activesupport/lib/active_support/reloader.rb +++ b/activesupport/lib/active_support/reloader.rb @@ -43,7 +43,13 @@ module ActiveSupport # Initiate a manual reload def self.reload! executor.wrap do - new.tap(&:run!).complete! + new.tap do |instance| + begin + instance.run! + ensure + instance.complete! + end + end end prepare! end diff --git a/activesupport/test/executor_test.rb b/activesupport/test/executor_test.rb index 6db6db4fa8..d9b389461a 100644 --- a/activesupport/test/executor_test.rb +++ b/activesupport/test/executor_test.rb @@ -1,6 +1,9 @@ require 'abstract_unit' class ExecutorTest < ActiveSupport::TestCase + class DummyError < RuntimeError + end + def test_wrap_invokes_callbacks called = [] executor.to_run { called << :run } @@ -35,6 +38,20 @@ class ExecutorTest < ActiveSupport::TestCase assert_equal [:run, :body, :complete], called end + def test_exceptions_unwind + called = [] + executor.to_run { called << :run_1 } + executor.to_run { raise DummyError } + executor.to_run { called << :run_2 } + executor.to_complete { called << :complete } + + assert_raises(DummyError) do + executor.wrap { called << :body } + end + + assert_equal [:run_1, :complete], called + end + def test_avoids_double_wrapping called = [] executor.to_run { called << :run } @@ -51,6 +68,96 @@ class ExecutorTest < ActiveSupport::TestCase assert_equal [:run, :early, :body, :late, :complete], called end + def test_hooks_carry_state + supplied_state = :none + + hook = Class.new do + define_method(:run) do + :some_state + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.register_hook(hook) + + executor.wrap { } + + assert_equal :some_state, supplied_state + end + + def test_nil_state_is_sufficient + supplied_state = :none + + hook = Class.new do + define_method(:run) do + nil + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.register_hook(hook) + + executor.wrap { } + + assert_equal nil, supplied_state + end + + def test_exception_skips_uninvoked_hook + supplied_state = :none + + hook = Class.new do + define_method(:run) do + :some_state + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.to_run do + raise DummyError + end + executor.register_hook(hook) + + assert_raises(DummyError) do + executor.wrap { } + end + + assert_equal :none, supplied_state + end + + def test_exception_unwinds_invoked_hook + supplied_state = :none + + hook = Class.new do + define_method(:run) do + :some_state + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.register_hook(hook) + executor.to_run do + raise DummyError + end + + assert_raises(DummyError) do + executor.wrap { } + end + + assert_equal :some_state, supplied_state + end + def test_separate_classes_can_wrap other_executor = Class.new(ActiveSupport::Executor) diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md index 327495704a..feee0f9920 100644 --- a/guides/source/3_1_release_notes.md +++ b/guides/source/3_1_release_notes.md @@ -558,4 +558,4 @@ Credits See the [full list of contributors to Rails](http://contributors.rubyonrails.org/) for the many people who spent many hours making Rails, the stable and robust framework it is. Kudos to all of them. -Rails 3.1 Release Notes were compiled by [Vijay Dev](https://github.com/vijaydev.) +Rails 3.1 Release Notes were compiled by [Vijay Dev](https://github.com/vijaydev) diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md index 3b926c04f0..6351ff57c1 100644 --- a/guides/source/5_0_release_notes.md +++ b/guides/source/5_0_release_notes.md @@ -439,10 +439,6 @@ Please refer to the [Changelog][active-record] for detailed changes. * Deprecated `ActiveRecord::Base.errors_in_transactional_callbacks=`. ([commit](https://github.com/rails/rails/commit/07d3d402341e81ada0214f2cb2be1da69eadfe72)) -* Deprecated passing of `start` value to `find_in_batches` and `find_each` - in favour of `begin_at` value. - ([Pull Request](https://github.com/rails/rails/pull/18961)) - * Deprecated `Relation#uniq` use `Relation#distinct` instead. ([commit](https://github.com/rails/rails/commit/adfab2dcf4003ca564d78d4425566dd2d9cd8b4f)) diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index ae204a55d6..745f09f523 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -526,7 +526,7 @@ Weak ETags have a leading `W/` to differentiate them from strong ETags. "618bbc92e2d35ea1945008b42799b0e7" → Strong ETag ``` -Unlike weak ETag, Strong ETag implies that response should be exactly same +Unlike weak ETag, strong ETag implies that response should be exactly the same and byte by byte identical. Useful when doing Range requests within a large video or PDF file. Some CDNs support only strong ETags, like Akamai. If you absolutely need to generate a strong ETag, it can be done as follows. diff --git a/guides/source/configuring.md b/guides/source/configuring.md index e80f994deb..6b9b95f1ab 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -352,7 +352,7 @@ The schema dumper adds one additional configuration option: * `config.action_controller.default_static_extension` configures the extension used for cached pages. Defaults to `.html`. -* `config.action_controller.include_all_helpers` configures whether all view helpers are available everywhere or are scoped to the corresponding controller. If set to `false`, `UsersHelper` methods are only available for views rendered as part of `UsersController`. If `true`, `UsersHelper` methods are available everywhere. The default is `true`. +* `config.action_controller.include_all_helpers` configures whether all view helpers are available everywhere or are scoped to the corresponding controller. If set to `false`, `UsersHelper` methods are only available for views rendered as part of `UsersController`. If `true`, `UsersHelper` methods are available everywhere. The default configuration behavior (when this option is not explicitly set to `true` or `false`) is that all view helpers are available to each controller. * `config.action_controller.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Controller. Set to `nil` to disable logging. diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index a615751eb5..ae631ae58d 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -223,8 +223,7 @@ the server. The "Welcome aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a -page. You can also click on the _About your application's environment_ link to -see a summary of your application's environment. +page. ### Say "Hello", Rails diff --git a/guides/source/testing.md b/guides/source/testing.md index e302611b2a..34c831c802 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -495,7 +495,8 @@ users(:david) users(:david).id # one can also access methods available on the User class -email(david.partner.email, david.location_tonight) +david = users(:david) +david.call(david.partner) ``` To get multiple fixtures at once, you can pass in a list of fixture names. For example: diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 34f2265108..0aed6c1351 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -62,18 +62,36 @@ module Rails ActiveSupport.run_load_hooks(:after_initialize, self) end + class MutexHook + def initialize(mutex = Mutex.new) + @mutex = mutex + end + + def run + @mutex.lock + end + + def complete(_state) + @mutex.unlock + end + end + + module InterlockHook + def self.run + ActiveSupport::Dependencies.interlock.start_running + end + + def self.complete(_state) + ActiveSupport::Dependencies.interlock.done_running + end + end + initializer :configure_executor_for_concurrency do |app| if config.allow_concurrency == false # User has explicitly opted out of concurrent request # handling: presumably their code is not threadsafe - mutex = Mutex.new - app.executor.to_run(prepend: true) do - mutex.lock - end - app.executor.to_complete(:after) do - mutex.unlock - end + app.executor.register_hook(MutexHook.new, outer: true) elsif config.allow_concurrency == :unsafe # Do nothing, even if we know this is dangerous. This is the @@ -86,12 +104,7 @@ module Rails # Without cache_classes + eager_load, the load interlock # is required for proper operation - app.executor.to_run(prepend: true) do - ActiveSupport::Dependencies.interlock.start_running - end - app.executor.to_complete(:after) do - ActiveSupport::Dependencies.interlock.done_running - end + app.executor.register_hook(InterlockHook, outer: true) end end end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 57309112b5..c947c062fa 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -1,5 +1,3 @@ -require 'open-uri' - module Rails module Generators module Actions diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt index 72258cc96b..d51f79bd49 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -8,8 +8,8 @@ <%%= stylesheet_link_tag 'application', media: 'all' %> <%- else -%> <%- if gemfile_entries.any? { |m| m.name == 'turbolinks' } -%> - <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => 'reload' %> - <%%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %> + <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> + <%%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%- else -%> <%%= stylesheet_link_tag 'application', media: 'all' %> <%%= javascript_include_tag 'application' %> diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 0572a23df9..2d9867fa9d 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -65,8 +65,8 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_assets run_generator - assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => 'reload'/) - assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track' => 'reload'/) + assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track': 'reload'/) + assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track': 'reload'/) assert_file("app/assets/stylesheets/application.css") assert_file("app/assets/javascripts/application.js") end |