From c7664d112fadb313146da33f48d1da318f249927 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Fri, 30 Jul 2010 07:14:48 +0200 Subject: [PATCH] Include application's helpers and router helpers by default, but include engine's ones for controllers inside isolated namespace --- actionmailer/lib/action_mailer/railtie.rb | 2 + .../action_mailer/railties/routes_helpers.rb | 12 ++ actionpack/lib/action_controller/base.rb | 8 +- .../lib/action_controller/metal/helpers.rb | 6 +- actionpack/lib/action_controller/railtie.rb | 3 +- .../railties/routes_helpers.rb | 17 +++ railties/lib/rails/engine.rb | 9 ++ railties/test/railties/engine_test.rb | 129 ++++++++++++++++++ 8 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 actionmailer/lib/action_mailer/railties/routes_helpers.rb create mode 100644 actionpack/lib/action_controller/railties/routes_helpers.rb diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index c888e51b93..26fe125fd8 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -1,5 +1,6 @@ require "action_mailer" require "rails" +require "action_mailer/railties/routes_helpers" module ActionMailer class Railtie < Rails::Railtie @@ -20,6 +21,7 @@ module ActionMailer ActiveSupport.on_load(:action_mailer) do include app.routes.url_helpers include app.routes.mounted_helpers(:app) + extend ::ActionMailer::Railties::RoutesHelpers options.each { |k,v| send("#{k}=", v) } end end diff --git a/actionmailer/lib/action_mailer/railties/routes_helpers.rb b/actionmailer/lib/action_mailer/railties/routes_helpers.rb new file mode 100644 index 0000000000..3464ec38e2 --- /dev/null +++ b/actionmailer/lib/action_mailer/railties/routes_helpers.rb @@ -0,0 +1,12 @@ +module ActionMailer + module Railties + module RoutesHelpers + def inherited(klass) + super(klass) + if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) } + klass.send(:include, namespace._railtie.routes.url_helpers) + end + end + end + end +end diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 7a1464c2aa..3560ac5b8c 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -223,9 +223,13 @@ module ActionController def self.inherited(klass) super - klass.helper :all if klass.superclass == ActionController::Base + if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) } + klass.helper(all_helpers_from_path(namespace._railtie.config.paths.app.helpers.to_a)) + else + klass.helper :all if klass.superclass == ActionController::Base + end end ActiveSupport.run_load_hooks(:action_controller, self) end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 4b6897c5dd..c5d7842db3 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -101,8 +101,12 @@ module ActionController # Extract helper names from files in app/helpers/**/*_helper.rb def all_application_helpers + all_helpers_from_path(helpers_path) + end + + def all_helpers_from_path(path) helpers = [] - Array.wrap(helpers_path).each do |path| + Array.wrap(path).each do |path| extract = /^#{Regexp.quote(path.to_s)}\/?(.*)_helper.rb$/ helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } end diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 7496dd57b2..23622b19e8 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -4,6 +4,7 @@ require "action_dispatch/railtie" require "action_view/railtie" require "active_support/deprecation/proxy_wrappers" require "active_support/deprecation" +require "action_controller/railties/routes_helpers" module ActionController class Railtie < Rails::Railtie @@ -50,7 +51,7 @@ module ActionController options.helpers_path ||= paths.app.helpers.to_a ActiveSupport.on_load(:action_controller) do - include app.routes.url_helpers + extend ::ActionController::Railties::RoutesHelpers.with(app.routes) include app.routes.mounted_helpers(:app) options.each { |k,v| send("#{k}=", v) } end diff --git a/actionpack/lib/action_controller/railties/routes_helpers.rb b/actionpack/lib/action_controller/railties/routes_helpers.rb new file mode 100644 index 0000000000..a23f703f0b --- /dev/null +++ b/actionpack/lib/action_controller/railties/routes_helpers.rb @@ -0,0 +1,17 @@ +module ActionController + module Railties + module RoutesHelpers + def self.with(routes) + Module.new do + define_method(:inherited) do |klass| + super(klass) + if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) } + routes = namespace._railtie.routes + end + klass.send(:include, routes.url_helpers) + end + end + end + end + end +end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 85ff09d2af..7f53e2dc72 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -199,6 +199,15 @@ module Rails @endpoint = endpoint if endpoint @endpoint end + + def isolated_engine_for(mod) + _engine = self + mod.singleton_class.instance_eval do + define_method(:_railtie) do + _engine + end + end + end end delegate :middleware, :root, :paths, :to => :config diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index d4ecdf4742..db610451bd 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -298,5 +298,134 @@ module RailtiesTest response = Rails.application.call(env) assert_equal response[2].path, File.join(@plugin.path, "public/bukkits.html") end + + test "shared engine should include application's helpers" do + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match "/foo" => "bukkits/foo#index", :as => "foo" + match "/foo/show" => "bukkits/foo#show" + end + RUBY + + app_file "app/helpers/some_helper.rb", <<-RUBY + module SomeHelper + def something + "Something... Something... Something..." + end + end + RUBY + + @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY + class Bukkits::FooController < ActionController::Base + def index + render :inline => "<%= something %>" + end + + def show + render :text => foo_path + end + end + RUBY + + boot_rails + + env = Rack::MockRequest.env_for("/foo") + response = Rails.application.call(env) + assert_equal "Something... Something... Something...", response[2].body + + env = Rack::MockRequest.env_for("/foo/show") + response = Rails.application.call(env) + assert_equal "/foo", response[2].body + end + + test "isolated engine should include only its own routes and helpers" do + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + isolated_engine_for Bukkits + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match "/bar" => "bar#index", :as => "bar" + mount Bukkits::Engine => "/bukkits", :as => "bukkits" + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + match "/foo" => "bukkits/foo#index", :as => "foo" + match "/foo/show" => "bukkits/foo#show" + match "/from_app" => "bukkits/foo#from_app" + match "/routes_helpers_in_view" => "bukkits/foo#routes_helpers_in_view" + end + RUBY + + app_file "app/helpers/some_helper.rb", <<-RUBY + module SomeHelper + def something + "Something... Something... Something..." + end + end + RUBY + + @plugin.write "app/helpers/engine_helper.rb", <<-RUBY + module EngineHelper + def help_the_engine + "Helped." + end + end + RUBY + + @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY + class Bukkits::FooController < ActionController::Base + def index + render :inline => "<%= help_the_engine %>" + end + + def show + render :text => foo_path + end + + def from_app + render :inline => "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>" + end + + def routes_helpers_in_view + render :inline => "<%= foo_path %>, <%= app.bar_path %>" + end + end + RUBY + + @plugin.write "app/mailers/bukkits/my_mailer.rb", <<-RUBY + module Bukkits + class MyMailer < ActionMailer::Base + end + end + RUBY + + boot_rails + + assert_equal Bukkits._railtie, Bukkits::Engine + assert ::Bukkits::MyMailer.method_defined?(:foo_path) + + env = Rack::MockRequest.env_for("/bukkits/from_app") + response = AppTemplate::Application.call(env) + assert_equal "false", response[2].body + + env = Rack::MockRequest.env_for("/bukkits/foo/show") + response = AppTemplate::Application.call(env) + assert_equal "/bukkits/foo", response[2].body + + env = Rack::MockRequest.env_for("/bukkits/foo") + response = AppTemplate::Application.call(env) + assert_equal "Helped.", response[2].body + + env = Rack::MockRequest.env_for("/bukkits/routes_helpers_in_view") + response = AppTemplate::Application.call(env) + assert_equal "/bukkits/foo, /bar", response[2].body + end end end