Properly reload routes defined in class definition

Sometimes it's easier to define routes inside Engine or
Application class definition (e.g. one file applications). The
problem with such case is that if there is a plugin that
has config/routes.rb file, it will trigger routes reload on application.
Since routes definition for application is not in config/routes.rb
file routes_reloader will fail to reload application's routes
properly. With this commit you can pass routes definition as a block
to routes method, which will allow to properly reload it:

class MyApp::Application < Rails::Application
  routes do
    resources :users
  end
end
This commit is contained in:
Piotr Sarnacki 2010-09-26 00:17:06 +02:00
parent 22b11a41cc
commit ec5d846ac6
4 changed files with 63 additions and 6 deletions

View File

@ -1,6 +1,7 @@
require 'rack/mount'
require 'forwardable'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
module ActionDispatch
module Routing

View File

@ -85,14 +85,25 @@ module Rails
end
def reload_routes!
routes_to_reload.each do |_routes, draw_block|
_routes = self.routes
_routes.disable_clear_and_finalize = true
_routes.clear!
_routes.draw(&draw_block) if draw_block
end
routes_reloader.paths.each { |path| load(path) }
routes_to_reload.each do |_routes, draw_block|
ActiveSupport.on_load(:action_controller) { _routes.finalize! }
end
ensure
routes_to_reload.each do |_routes, draw_block|
_routes.disable_clear_and_finalize = false
end
end
def routes_to_reload
@routes_to_reload ||= {}
end
def initialize!
raise "Application has been already initialized." if @initialized

View File

@ -399,8 +399,10 @@ module Rails
}
end
def routes
def routes(&block)
@routes ||= ActionDispatch::Routing::RouteSet.new
self.routes_draw_block = block if block_given?
@routes
end
def initializers
@ -447,6 +449,7 @@ module Rails
end
initializer :add_routing_paths do |app|
app.routes_to_reload[self.routes] = routes_draw_block
paths.config.routes.to_a.each do |route|
app.routes_reloader.paths.unshift(route) if File.exists?(route)
end
@ -499,6 +502,8 @@ module Rails
end
protected
attr_accessor :routes_draw_block
def find_root_with_flag(flag, default=nil)
root_path = self.class.called_from

View File

@ -663,5 +663,45 @@ module RailtiesTest
assert_equal AppTemplate._railtie, AppTemplate::Engine
end
test "properly reload routes" do
# when routes are inside application class definition
# they should not be reloaded when engine's routes
# file has changed
add_to_config <<-RUBY
routes do
mount lambda{|env| [200, {}, ["foo"]]} => "/foo"
mount Bukkits::Engine => "/bukkits"
end
RUBY
FileUtils.rm(File.join(app_path, "config/routes.rb"))
@plugin.write "config/routes.rb", <<-RUBY
Bukkits::Engine.routes.draw do
mount lambda{|env| [200, {}, ["bar"]]} => "/bar"
end
RUBY
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
namespace(Bukkits)
end
end
RUBY
require 'rack/test'
extend Rack::Test::Methods
boot_rails
require "#{rails_root}/config/environment"
get "/foo"
assert_equal "foo", last_response.body
get "/bukkits/bar"
assert_equal "bar", last_response.body
end
end
end