module ActionDispatch::Routing::Mapper::Scoping
def constraints(constraints = {})
resources :iphones
constraints(Iphone) do
This class is then used like this:
An expected place for this code would be +lib/constraints+.
end
end
request.env["HTTP_USER_AGENT"] =~ /iPhone/
def self.matches(request)
class Iphone
if the user should be given access to that route, or +false+ if the user should not.
This class must have a +matches?+ method defined on it which either returns +true+
You are able to move this logic out into a class if it is too complex for routes.
end
resources :iphones
constraints(lambda { |req| req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do
Requests to routes can be constrained based on specific critera:
=== Dynamic request matching
where as any user connecting outside of this range will be told there is no such route.
Any user connecting from the 192.168.* range will be able to see this resource,
end
resources :posts
constraints(:ip => /192.168.\d+.\d+/) do
Routes can also be constrained to an IP or a certain range of IP addresses:
=== Restricting based on IP
end
resources :comments
constraints(:post_id => /\d+\.\d+) do
resources :posts do
You may use this to also resrict other parameters:
The +id+ parameter must match the constraint passed in for this example.
Now routes such as +/posts/1+ will no longer be valid, but +/posts/1.1+ will be.
end
resources :posts
constraints(:id => /\d+\.\d+) do
For instance, in order to change the routes to allow for a dot character in the +id+ parameter:
Allows you to constrain the nested routes based on a set of rules.
=== Parameter Restriction
def constraints(constraints = {}) scope(:constraints => constraints) { yield } end
def controller(controller, options={})
match "bacon", :action => "bacon"
controller "food" do
Example:
Scopes routes to a specific controller
def controller(controller, options={}) options[:controller] = controller scope(options) { yield } end
def defaults(defaults = {})
end
match 'scoped_pages/(:id)', :to => 'pages#show'
defaults :id => 'home' do
Allows you to set default parameters for a route, such as this:
def defaults(defaults = {}) scope(:defaults => defaults) { yield } end
def initialize(*args) #:nodoc:
def initialize(*args) #:nodoc: @scope = {} super end
def merge_as_scope(parent, child)
def merge_as_scope(parent, child) parent ? "#{parent}_#{child}" : child end
def merge_blocks_scope(parent, child)
def merge_blocks_scope(parent, child) merged = parent ? parent.dup : [] merged << child if child merged end
def merge_constraints_scope(parent, child)
def merge_constraints_scope(parent, child) merge_options_scope(parent, child) end
def merge_controller_scope(parent, child)
def merge_controller_scope(parent, child) child end
def merge_defaults_scope(parent, child)
def merge_defaults_scope(parent, child) merge_options_scope(parent, child) end
def merge_module_scope(parent, child)
def merge_module_scope(parent, child) parent ? "#{parent}/#{child}" : child end
def merge_options_scope(parent, child)
def merge_options_scope(parent, child) (parent || {}).except(*override_keys(child)).merge(child) end
def merge_path_names_scope(parent, child)
def merge_path_names_scope(parent, child) merge_options_scope(parent, child) end
def merge_path_scope(parent, child)
def merge_path_scope(parent, child) Mapper.normalize_path("#{parent}/#{child}") end
def merge_shallow_path_scope(parent, child)
def merge_shallow_path_scope(parent, child) Mapper.normalize_path("#{parent}/#{child}") end
def merge_shallow_prefix_scope(parent, child)
def merge_shallow_prefix_scope(parent, child) parent ? "#{parent}_#{child}" : child end
def merge_shallow_scope(parent, child)
def merge_shallow_scope(parent, child) child ? true : false end
def namespace(path, options = {})
[:shallow_path]
Routing helpers such as +admin_posts_path+ will now be +sekret_posts_path+.
end
resources :posts
namespace :admin, :as => "sekret" do
Changes the name used in routing helpers for this namespace.
[:as]
end
# code go here
class Sekret::PostsController < ApplicationController
The +PostsController+ here should go in the +Sekret+ namespace and so it should be defined like this:
end
resources :posts
namespace :admin, :module => "sekret" do
The namespace for the controllers.
[:module]
All routes for the above +resources+ will be accessible through +/sekret/posts+, rather than +/admin/posts+
end
resources :posts
namespace :admin, :path => "sekret" do
The path prefix for the routes.
[:path]
The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+ options all default to the name of the namespace.
=== Supported options
admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"}
admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"}
admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"}
edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"}
new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"}
admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"}
admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"}
This generates the following routes:
end
resources :posts
namespace :admin do
Scopes routes to a specific namespace. For example:
def namespace(path, options = {}) path = path.to_s options = { :path => path, :as => path, :module => path, :shallow_path => path, :shallow_prefix => path }.merge!(options) scope(options) { yield } end
def override_keys(child)
def override_keys(child) child.key?(:only) || child.key?(:except) ? [:only, :except] : [] end
def scope(*args)
comment PUT /sekret/comments/:id(.:format)
comment GET /sekret/comments/:id(.:format)
edit_comment GET /sekret/comments/:id/edit(.:format)
new_post_comment GET /sekret/posts/:post_id/comments/new(.:format)
post_comments POST /sekret/posts/:post_id/comments(.:format)
post_comments GET /sekret/posts/:post_id/comments(.:format)
The +comments+ resource here will have the following routes generated for it:
end
resources :comments, :shallow => true
resources :posts do
scope :shallow_path => "sekret" do
Prefixes nested shallow routes with the specified path.
[:shallow_path]
Helpers such as +posts_path+ will now be +sekret_posts_path+
end
resources :posts
scope :as => "sekret" do
Prefixes the routing helpers in this scope with the specified label.
[:as]
This will prefix all of the +posts+ resource's requests with '/admin'
end
resources :posts
scope :path => "/admin" do
If you want to prefix the route, you could use
[:path]
end
resources :posts
scope :module => "admin" do
Admin::PostsController, you could use
If you want to route /posts (without the prefix /admin) to
[:module]
=== Supported options
rather than /accounts/rails/projects/2.
The difference here being that the routes generated are like /rails/projects/2,
This generates helpers such as +account_projects_path+, just like +resources+ does.
end
resources :projects
scope :path => ":account_id", :as => "account" do
Take the following route definition as an example:
Used to scope a set of routes to particular constraints.
def scope(*args) options = args.extract_options! options = options.dup if name_prefix = options.delete(:name_prefix) options[:as] ||= name_prefix ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new router syntax. Use :as instead.", caller end options[:path] = args.first if args.first.is_a?(String) recover = {} options[:constraints] ||= {} unless options[:constraints].is_a?(Hash) block, options[:constraints] = options[:constraints], {} end scope_options.each do |option| if value = options.delete(option) recover[option] = @scope[option] @scope[option] = send("merge_#{option}_scope", @scope[option], value) end end recover[:block] = @scope[:blocks] @scope[:blocks] = merge_blocks_scope(@scope[:blocks], block) recover[:options] = @scope[:options] @scope[:options] = merge_options_scope(@scope[:options], options) yield self ensure scope_options.each do |option| @scope[option] = recover[option] if recover.has_key?(option) end @scope[:options] = recover[:options] @scope[:blocks] = recover[:block] end
def scope_options
def scope_options @scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym } end