From 38af3540ae53b9f2fbdb649a68cde3edf182fe67 Mon Sep 17 00:00:00 2001
From: kennyj <kennyj@gmail.com>
Date: Tue, 29 May 2012 23:31:27 +0900
Subject: backport runner fixes to 3-2-stable

Add a runner hook to Rails::Application and Rails::Engine that requires
ActiveRecord::Base to avoid circular constant loading when using observers.

This commit backports cc7dd66, c0ba0f0 and 8d01c61.
---
 activerecord/CHANGELOG.md                 |  3 +++
 activerecord/lib/active_record/railtie.rb |  6 ++++++
 railties/CHANGELOG.md                     |  4 ++++
 railties/lib/rails/application.rb         | 11 +++++++++++
 railties/lib/rails/commands/runner.rb     |  1 +
 railties/lib/rails/engine.rb              |  5 +++++
 railties/lib/rails/railtie.rb             | 10 ++++++++++
 railties/test/application/rake_test.rb    | 22 ++++++++++++++++++++++
 railties/test/application/runner_test.rb  | 10 ++++++++++
 railties/test/railties/railtie_test.rb    | 16 ++++++++++++++++
 10 files changed, 88 insertions(+)

diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 0b22939884..3f91c0549e 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,8 @@
 ## Rails 3.2.10 (unreleased)
 
+*   Require ActiveRecord::Base in railtie hooks for rake_tasks, console and runner to
+    avoid circular constant loading issues. [Backport #7695] [Fixes #7683 and #882] *Ben Holley*
+
 *   Recognize migrations placed in directories containing numbers and 'rb'.
     Fix #8492
     Backport of #8500
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 13b7c6e214..4e39654e5b 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -30,6 +30,7 @@ module ActiveRecord
     )
 
     rake_tasks do
+      require "active_record/base"
       load "active_record/railties/databases.rake"
     end
 
@@ -38,9 +39,14 @@ module ActiveRecord
     # first time. Also, make it output to STDERR.
     console do |app|
       require "active_record/railties/console_sandbox" if app.sandbox?
+      require "active_record/base"
       ActiveRecord::Base.logger = Logger.new(STDERR)
     end
 
+    runner do |app|
+      require "active_record/base"
+    end
+
     initializer "active_record.initialize_timezone" do
       ActiveSupport.on_load(:active_record) do
         self.time_zone_aware_attributes = true
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 9110fdc673..c87b050d8b 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,7 @@
+## Rails 3.2.10 (unreleased) ##
+
+*   Add support for runner hook. [Backport: #7695] *Ben Holley*
+
 ## Rails 3.2.9 (Nov 12, 2012) ##
 
 *   Engines with a dummy app include the rake tasks of dependencies in the app namespace. [Backport: #8262]
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 854ac2cbbc..cc53009e80 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -154,6 +154,14 @@ module Rails
       self
     end
 
+    # Load the application runner and invoke the registered hooks.
+    # Check <tt>Rails::Railtie.runner</tt> for more info.
+    def load_runner(app=self)
+      initialize_runner
+      super
+      self
+    end
+
     # Rails.application.env_config stores some of the Rails initial environment parameters.
     # Currently stores:
     #
@@ -305,6 +313,9 @@ module Rails
       require "rails/console/helpers"
     end
 
+    def initialize_runner #:nodoc:
+    end
+
     def build_original_fullpath(env)
       path_info    = env["PATH_INFO"]
       query_string = env["QUERY_STRING"]
diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb
index e8cc5d9e3b..a694218695 100644
--- a/railties/lib/rails/commands/runner.rb
+++ b/railties/lib/rails/commands/runner.rb
@@ -42,6 +42,7 @@ ENV["RAILS_ENV"] = options[:environment]
 
 require APP_PATH
 Rails.application.require_environment!
+ Rails.application.load_runner
 
 if code_or_file.nil?
   $stderr.puts "Run '#{$0} -h' for help."
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 993dfe43ee..77f335e45f 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -430,6 +430,11 @@ module Rails
       super
     end
 
+    def load_runner(app=self)
+      railties.all { |r| r.load_runner(app) }
+      super
+    end
+
     def eager_load!
       railties.all(&:eager_load!)
 
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 07a122e7d0..9eb7e7c65d 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -145,6 +145,12 @@ module Rails
         @load_console
       end
 
+      def runner(&blk)
+        @load_runner ||= []
+        @load_runner << blk if blk
+        @load_runner
+      end
+
       def generators(&blk)
         @generators ||= []
         @generators << blk if blk
@@ -179,6 +185,10 @@ module Rails
       self.class.console.each { |block| block.call(app) }
     end
 
+    def load_runner(app=self)
+      self.class.runner.each { |block| block.call(app) }
+    end
+
     def load_tasks(app=self)
       extend Rake::DSL if defined? Rake::DSL
       self.class.rake_tasks.each { |block| self.instance_exec(app, &block) }
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index ab9084df55..ddabe2f07c 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -162,5 +162,27 @@ module ApplicationTests
         end
       end
     end
+
+    def test_load_activerecord_base_when_we_use_observers
+      Dir.chdir(app_path) do
+        `bundle exec rails g model user;
+         bundle exec rake db:migrate;
+         bundle exec rails g observer user;`
+
+        add_to_config "config.active_record.observers = :user_observer"
+
+        assert_equal "0", `bundle exec rails r "puts User.count"`.strip
+
+        app_file "lib/tasks/count_user.rake", <<-RUBY
+          namespace :user do
+            task :count => :environment do
+              puts User.count
+            end
+          end
+        RUBY
+
+        assert_equal "0", `bundle exec rake user:count`.strip
+      end
+    end
   end
 end
diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb
index 4468fa295e..d086f13c82 100644
--- a/railties/test/application/runner_test.rb
+++ b/railties/test/application/runner_test.rb
@@ -57,5 +57,15 @@ module ApplicationTests
 
       assert_match "script/program_name.rb", Dir.chdir(app_path) { `bundle exec rails runner "script/program_name.rb"` }
     end
+
+    def test_with_hook
+      add_to_config <<-RUBY
+        runner do |app|
+          app.config.ran = true
+        end
+      RUBY
+
+      assert_match "true", Dir.chdir(app_path) { `bundle exec rails runner "puts Rails.application.config.ran"` }
+    end
   end
 end
diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb
index 55f85c7202..335a74a609 100644
--- a/railties/test/railties/railtie_test.rb
+++ b/railties/test/railties/railtie_test.rb
@@ -163,6 +163,22 @@ module RailtiesTest
       assert $ran_block
     end
 
+    test "runner block is executed when MyApp.load_runner is called" do
+      $ran_block = false
+
+      class MyTie < Rails::Railtie
+        runner do
+          $ran_block = true
+        end
+      end
+
+      require "#{app_path}/config/environment"
+
+      assert !$ran_block
+      AppTemplate::Application.load_runner
+      assert $ran_block
+    end
+
     test "railtie can add initializers" do
       $ran_block = false
 
-- 
cgit v1.2.3