您可能希望将一组控制器组织到一个命名空间下。最常见的是,您可能希望将一组管理控制器组织到一个 admin 命名空间下。您会将这些控制器放在 app/controllers/admin 目录下,并在路由器中将它们组合起来。
namespace "admin" do resources :posts, :comments end
这将为 posts 和 comments 控制器中的每一个控制器创建一系列路由。对于 Admin::PostsController,Rails 会创建
GET /admin/posts GET /admin/posts/new POST /admin/posts GET /admin/posts/1 GET /admin/posts/1/edit PATCH/PUT /admin/posts/1 DELETE /admin/posts/1
如果您想将 /posts (不带 /admin 前缀) 路由到 Admin::PostsController,您可以使用
scope module: "admin" do resources :posts end
或者,对于单个情况
resources :posts, module: "admin"
如果您想将 /admin/posts 路由到 PostsController (不带 Admin:: 模块前缀),您可以使用
scope "/admin" do resources :posts end
或者,对于单个情况
resources :posts, path: "/admin/posts"
在所有这些情况下,命名路由与不使用 scope 时保持相同。在最后一种情况下,以下路径映射到 PostsController
GET /admin/posts GET /admin/posts/new POST /admin/posts GET /admin/posts/1 GET /admin/posts/1/edit PATCH/PUT /admin/posts/1 DELETE /admin/posts/1
- C
- D
- N
- S
实例公共方法
constraints(constraints = {}, &block) 链接
参数限制¶ ↑
允许您根据一组规则限制嵌套路由。例如,为了修改路由以允许在 id 参数中包含点字符
constraints(id: /\d+\.\d+/) do resources :posts end
现在,像 /posts/1 这样的路由将不再有效,但 /posts/1.1 将有效。在这个例子中,id 参数必须与传入的约束匹配。
您也可以使用此方法限制其他参数
resources :posts do constraints(post_id: /\d+\.\d+/) do resources :comments end end
基于 IP 进行限制¶ ↑
路由也可以限制到特定的 IP 地址或某个 IP 地址范围
constraints(ip: /192\.168\.\d+\.\d+/) do resources :posts end
来自 192.168.* 范围内的任何用户都可以看到此资源,而来自此范围外的任何用户都将被告知不存在此路由。
动态请求匹配¶ ↑
可以根据特定标准限制对路由的请求
constraints(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do resources :iphones end
如果逻辑过于复杂,您可以将其移到一个类中。这个类必须定义一个 matches? 方法,该方法返回 true (如果用户应该被授予对该路由的访问权限) 或 false (如果用户不应该被授予访问权限)。
class Iphone def self.matches?(request) /iPhone/.match?(request.env["HTTP_USER_AGENT"]) end end
放置此类代码的预期位置是 lib/constraints。
然后这样使用此类
constraints(Iphone) do resources :iphones end
来源: 显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1176 def constraints(constraints = {}, &block) scope(constraints: constraints, &block) end
controller(controller) 链接
将路由作用于特定控制器
controller "food" do match "bacon", action: :bacon, via: :get end
来源: 显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1052 def controller(controller) @scope = @scope.new(controller: controller) yield ensure @scope = @scope.parent end
defaults(defaults = {}) 链接
允许您为路由设置默认参数,例如
defaults id: 'home' do match 'scoped_pages/(:id)', to: 'pages#show' end
使用此方法,这里的 :id 参数将默认为 ‘home’。
来源: 显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1187 def defaults(defaults = {}) @scope = @scope.new(defaults: merge_defaults_scope(@scope[:defaults], defaults)) yield ensure @scope = @scope.parent end
namespace(name, deprecated_options = nil, as: DEFAULT, path: DEFAULT, shallow_path: DEFAULT, shallow_prefix: DEFAULT, **options, &block) 链接
将路由作用于特定命名空间。例如
namespace :admin do resources :posts end
这将生成以下路由
admin_posts GET /admin/posts(.:format) admin/posts#index
admin_posts POST /admin/posts(.:format) admin/posts#create
new_admin_post GET /admin/posts/new(.:format) admin/posts#new
edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
admin_post GET /admin/posts/:id(.:format) admin/posts#show
admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
选项¶ ↑
:path、:as、:module、:shallow_path 和 :shallow_prefix 选项都默认使用命名空间的名称。
有关选项,请参阅 Base#match。有关 :shallow_path 选项,请参阅 Resources#resources。
# accessible through /sekret/posts rather than /admin/posts namespace :admin, path: "sekret" do resources :posts end # maps to Sekret::PostsController rather than Admin::PostsController namespace :admin, module: "sekret" do resources :posts end # generates sekret_posts_path rather than admin_posts_path namespace :admin, as: "sekret" do resources :posts end
来源: 显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1097 def namespace(name, deprecated_options = nil, as: DEFAULT, path: DEFAULT, shallow_path: DEFAULT, shallow_prefix: DEFAULT, **options, &block) if deprecated_options.is_a?(Hash) as = assign_deprecated_option(deprecated_options, :as, :namespace) if deprecated_options.key?(:as) path ||= assign_deprecated_option(deprecated_options, :path, :namespace) if deprecated_options.key?(:path) shallow_path ||= assign_deprecated_option(deprecated_options, :shallow_path, :namespace) if deprecated_options.key?(:shallow_path) shallow_prefix ||= assign_deprecated_option(deprecated_options, :shallow_prefix, :namespace) if deprecated_options.key?(:shallow_prefix) assign_deprecated_options(deprecated_options, options, :namespace) end name = name.to_s options[:module] ||= name as = name if as == DEFAULT path = name if path == DEFAULT shallow_path = path if shallow_path == DEFAULT shallow_prefix = as if shallow_prefix == DEFAULT path_scope(path) do scope(**options, as:, shallow_path:, shallow_prefix:, &block) end end
scope(*args, only: nil, except: nil, **options) 链接
使用给定的默认选项作用于一组路由。
以以下路由定义为例
scope path: ":account_id", as: "account" do resources :projects end
这将生成像 account_projects_path 这样的辅助方法,就像 resources 所做的一样。不同之处在于生成的路由是 /:account_id/projects,而不是 /accounts/:account_id/projects。
选项¶ ↑
接受与 Base#match 和 Resources#resources 相同的选项。
# route /posts (without the prefix /admin) to Admin::PostsController scope module: "admin" do resources :posts end # prefix the posts resource's requests with '/admin' scope path: "/admin" do resources :posts end # prefix the routing helper name: sekret_posts_path instead of posts_path scope as: "sekret" do resources :posts end
来源: 显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 989 def scope(*args, only: nil, except: nil, **options) if args.grep(Hash).any? && (deprecated_options = args.extract_options!) only ||= assign_deprecated_option(deprecated_options, :only, :scope) only ||= assign_deprecated_option(deprecated_options, :except, :scope) assign_deprecated_options(deprecated_options, options, :scope) end scope = {} options[:path] = args.flatten.join("/") if args.any? options[:constraints] ||= {} unless nested_scope? options[:shallow_path] ||= options[:path] if options.key?(:path) options[:shallow_prefix] ||= options[:as] if options.key?(:as) end if options[:constraints].is_a?(Hash) defaults = options[:constraints].select do |k, v| URL_OPTIONS.include?(k) && (v.is_a?(String) || v.is_a?(Integer)) end options[:defaults] = defaults.merge(options[:defaults] || {}) else block, options[:constraints] = options[:constraints], {} end if only || except scope[:action_options] = { only:, except: } end if options.key? :anchor raise ArgumentError, "anchor is ignored unless passed to `match`" end @scope.options.each do |option| if option == :blocks value = block elsif option == :options value = options else value = options.delete(option) { POISON } end unless POISON == value scope[option] = send("merge_#{option}_scope", @scope[option], value) end end @scope = @scope.new scope yield self ensure @scope = @scope.parent end