Skip to content

Commit

Permalink
Allow loading external route files from the router
Browse files Browse the repository at this point in the history
This feature enables the ability to load an
external routes file from the router via:
  draw :filename

External routes files go in +config/routes+. This
feature works in both engines and applications.
  • Loading branch information
wycats committed Apr 25, 2012
1 parent 3c100cf commit 6acebb3
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 3 deletions.
16 changes: 16 additions & 0 deletions actionpack/lib/action_dispatch/routing/mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,21 @@ def shallow?
parent_resource.instance_of?(Resource) && @scope[:shallow]
end

def draw(name)
path = @draw_paths.find do |path|
path.join("#{name}.rb").file?
end

unless path
msg = "Your router tried to #draw the external file #{name}.rb,\n" \
"but the file was not found in:\n\n"
msg += @draw_paths.map { |path| " * #{path}" }.join("\n")
raise msg
end

instance_eval(path.join("#{name}.rb").read)
end

# match 'path' => 'controller#action'
# match 'path', to: 'controller#action'
# match 'path', 'otherpath', on: :member, via: :get
Expand Down Expand Up @@ -1554,6 +1569,7 @@ def name_for_action(as, action) #:nodoc:

def initialize(set) #:nodoc:
@set = set
@draw_paths = set.draw_paths
@scope = { :path_names => @set.resources_path_names }
end

Expand Down
2 changes: 2 additions & 0 deletions actionpack/lib/action_dispatch/routing/route_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ def optimized_helper(route)
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
attr_accessor :disable_clear_and_finalize, :resources_path_names
attr_accessor :default_url_options, :request_class, :valid_conditions
attr_accessor :draw_paths

alias :routes :set

Expand All @@ -266,6 +267,7 @@ def initialize(request_class = ActionDispatch::Request)
self.named_routes = NamedRouteCollection.new
self.resources_path_names = self.class.default_resources_path_names.dup
self.default_url_options = {}
self.draw_paths = []

self.request_class = request_class
@valid_conditions = {}
Expand Down
18 changes: 18 additions & 0 deletions guides/source/routing.textile
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,24 @@ end

This will create routing helpers such as +magazine_periodical_ads_url+ and +edit_magazine_periodical_ad_path+.

h3. Breaking Up a Large Route File

If you have a large route file that you would like to break up into multiple files, you can use the +#draw+ method in your router:

<ruby>
draw :admin
</ruby>

Then, create a file called +config/routes/admin.rb+. Name the file the same as the symbol passed to the +draw+ method). You can then use the normal routing DSL inside that file:

<ruby>
# in config/routes/admin.rb

namespace :admin do
resources :posts
end
</ruby>

h3. Inspecting and Testing Routes

Rails offers facilities for inspecting and testing your routes.
Expand Down
3 changes: 2 additions & 1 deletion railties/lib/rails/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ def env_config

def routes
@routes ||= ActionDispatch::Routing::RouteSet.new
@routes.draw_paths.concat paths["config/routes"].paths
@routes.append(&Proc.new) if block_given?
@routes
end
Expand Down Expand Up @@ -544,7 +545,7 @@ def load_seed
end

initializer :add_routing_paths do |app|
paths = self.paths["config/routes"].existent
paths = self.paths["config/routes.rb"].existent

if routes? || paths.any?
app.routes_reloader.paths.unshift(*paths)
Expand Down
3 changes: 2 additions & 1 deletion railties/lib/rails/engine/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ def paths
paths.add "config/environments", :glob => "#{Rails.env}.rb"
paths.add "config/initializers", :glob => "**/*.rb"
paths.add "config/locales", :glob => "*.{rb,yml}"
paths.add "config/routes", :with => "config/routes.rb"
paths.add "config/routes.rb"
paths.add "config/routes", :glob => "**/*.rb"
paths.add "db"
paths.add "db/migrate"
paths.add "db/seeds", :with => "db/seeds.rb"
Expand Down
12 changes: 11 additions & 1 deletion railties/lib/rails/paths.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "pathname"

module Rails
module Paths
# This object is an extended hash that behaves as root of the <tt>Rails::Paths</tt> system.
Expand Down Expand Up @@ -114,7 +116,7 @@ def filter_by(constraint)
class Path
include Enumerable

attr_reader :path
attr_reader :path, :root
attr_accessor :glob

def initialize(root, current, paths, options = {})
Expand Down Expand Up @@ -180,6 +182,14 @@ def to_ary
@paths
end

def paths
raise "You need to set a path root" unless @root.path

map do |p|
Pathname.new(@root.path).join(p)
end
end

# Expands all paths against the root and return all unique values.
def expanded
raise "You need to set a path root" unless @root.path
Expand Down
2 changes: 2 additions & 0 deletions railties/test/application/paths_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def assert_not_in_load_path(*path)
assert_path @paths["config/locales"], "config/locales/en.yml"
assert_path @paths["config/environment"], "config/environment.rb"
assert_path @paths["config/environments"], "config/environments/development.rb"
assert_path @paths["config/routes.rb"], "config/routes.rb"
assert_path @paths["config/routes"], "config/routes"

assert_equal root("app", "controllers"), @paths["app/controllers"].expanded.first
end
Expand Down
24 changes: 24 additions & 0 deletions railties/test/application/routing_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,30 @@ def index
assert_equal 'WIN', last_response.body
end

test "routes drawing from config/routes" do
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
draw :external
end
RUBY

app_file 'config/routes/external.rb', <<-RUBY
get ':controller/:action'
RUBY

controller :success, <<-RUBY
class SuccessController < ActionController::Base
def index
render :text => "success!"
end
end
RUBY

app 'development'
get '/success/index'
assert_equal 'success!', last_response.body
end

{"development" => "baz", "production" => "bar"}.each do |mode, expected|
test "reloads routes when configuration is changed in #{mode}" do
controller :foo, <<-RUBY
Expand Down
2 changes: 2 additions & 0 deletions railties/test/paths_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def setup
test "creating a root level path" do
@root.add "app"
assert_equal ["/foo/bar/app"], @root["app"].to_a
assert_equal [Pathname.new("/foo/bar/app")], @root["app"].paths
end

test "creating a root level path with options" do
Expand Down Expand Up @@ -191,6 +192,7 @@ def setup
@root["app"] = "/app"
@root["app"].glob = "*.rb"
assert_equal "*.rb", @root["app"].glob
assert_equal [Pathname.new("/app")], @root["app"].paths
end

test "it should be possible to override a path's default glob without assignment" do
Expand Down

0 comments on commit 6acebb3

Please sign in to comment.