资源路由允许您快速为给定的资源控制器声明所有常用路由。与其为 index、show、new、edit、create、update 和 destroy 操作分别声明路由,不如用一行代码声明所有资源路由。
resources :photos
有时,您会遇到客户端始终在不引用 ID 的情况下查找的资源。一个常见的例子是,/profile 始终显示当前登录用户的个人资料。在这种情况下,您可以使用单数资源来映射 /profile(而不是 /profile/:id)到 show 操作。
resource :profile
拥有逻辑上属于其他资源子资源的资源是很常见的。
resources :magazines do resources :ads end
您可能希望将一组控制器组织到一个命名空间下。最常见的是,您可能希望将一组管理控制器组织到一个 admin 命名空间下。您会将这些控制器放在 app/controllers/admin 目录下,并在路由器中将它们组合起来。
namespace "admin" do resources :posts, :comments end
默认情况下,:id 参数不接受点。如果您需要将点作为 :id 参数的一部分,请添加一个覆盖此限制的约束,例如:
resources :articles, id: /[^\/]+/
这允许在您的 :id 中使用除斜杠以外的任何字符。
- A
- C
- D
- M
- N
- R
- S
- W
常量
| CANONICAL_ACTIONS | = | %w(index create new show update destroy) |
| RESOURCE_OPTIONS | = | [:as, :controller, :path, :only, :except, :param, :concerns] |
| VALID_ON_OPTIONS | = | [:new, :collection, :member] |
|
||
实例公共方法
collection(&block) Link
To add a route to the collection
resources :photos do collection do get 'search' end end
这将使 Rails 能够识别 /photos/search 这样的路径(GET 请求),并将其路由到 PhotosController 的 search 操作。它还将创建 search_photos_url 和 search_photos_path 路由助手。
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1707 def collection(&block) unless resource_scope? raise ArgumentError, "can't use collection outside resource(s) scope" end with_scope_level(:collection) do path_scope(parent_resource.collection_scope, &block) end end
draw(name) Link
使用给定的 name 加载另一个路由文件,该文件位于 config/routes 目录中。在该文件中,您可以使用正常的路由 DSL,但不要将其包含在 Rails.application.routes.draw 块中。
# config/routes.rb Rails.application.routes.draw do draw :admin # Loads `config/routes/admin.rb` draw "third_party/some_gem" # Loads `config/routes/third_party/some_gem.rb` end # config/routes/admin.rb namespace :admin do resources :accounts end # config/routes/third_party/some_gem.rb mount SomeGem::Engine, at: "/some_gem"
CAUTION: Use this feature with care. Having multiple routes files can negatively impact discoverability and readability. For most applications —even those with a few hundred routes — it’s easier for developers to have a single routes file.
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1816 def draw(name) path = @draw_paths.find do |_path| File.exist? "#{_path}/#{name}.rb" 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 ArgumentError, msg end route_path = "#{path}/#{name}.rb" instance_eval(File.read(route_path), route_path.to_s) end
match(*path_or_actions, as: DEFAULT, via: nil, to: nil, controller: nil, action: nil, on: nil, defaults: nil, constraints: nil, anchor: nil, format: nil, path: nil, internal: nil, **mapping, &block) Link
Matches a URL pattern to one or more routes. For more information, see match.
match 'path', to: 'controller#action', via: :post match 'otherpath', on: :member, via: :get
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1837 def match(*path_or_actions, as: DEFAULT, via: nil, to: nil, controller: nil, action: nil, on: nil, defaults: nil, constraints: nil, anchor: nil, format: nil, path: nil, internal: nil, **mapping, &block) if path_or_actions.grep(Hash).any? && (deprecated_options = path_or_actions.extract_options!) as = assign_deprecated_option(deprecated_options, :as, :match) if deprecated_options.key?(:as) via ||= assign_deprecated_option(deprecated_options, :via, :match) to ||= assign_deprecated_option(deprecated_options, :to, :match) controller ||= assign_deprecated_option(deprecated_options, :controller, :match) action ||= assign_deprecated_option(deprecated_options, :action, :match) on ||= assign_deprecated_option(deprecated_options, :on, :match) defaults ||= assign_deprecated_option(deprecated_options, :defaults, :match) constraints ||= assign_deprecated_option(deprecated_options, :constraints, :match) anchor = assign_deprecated_option(deprecated_options, :anchor, :match) if deprecated_options.key?(:anchor) format = assign_deprecated_option(deprecated_options, :format, :match) if deprecated_options.key?(:format) path ||= assign_deprecated_option(deprecated_options, :path, :match) internal ||= assign_deprecated_option(deprecated_options, :internal, :match) assign_deprecated_options(deprecated_options, mapping, :match) end raise ArgumentError, "Wrong number of arguments (expect 1, got #{path_or_actions.count})" if path_or_actions.count > 1 if path_or_actions.none? && mapping.any? hash_path, hash_to = mapping.find { |key, _| key.is_a?(String) } if hash_path.nil? raise ArgumentError, "Route path not specified" else mapping.delete(hash_path) end if hash_path path_or_actions.push hash_path case hash_to when Symbol action ||= hash_to when String if hash_to.include?("#") to ||= hash_to else controller ||= hash_to end else to ||= hash_to end end end path_or_actions.each do |path_or_action| if defaults defaults(defaults) { map_match(path_or_action, as:, via:, to:, controller:, action:, on:, constraints:, anchor:, format:, path:, internal:, mapping:, &block) } else map_match(path_or_action, as:, via:, to:, controller:, action:, on:, constraints:, anchor:, format:, path:, internal:, mapping:, &block) end end end
member(&block) Link
To add a member route, add a member block into the resource block
resources :photos do member do get 'preview' end end
This will recognize /photos/1/preview with GET, and route to the preview action of PhotosController. It will also create the preview_photo_url and preview_photo_path helpers.
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1728 def member(&block) unless resource_scope? raise ArgumentError, "can't use member outside resource(s) scope" end with_scope_level(:member) do if shallow? shallow_scope { path_scope(parent_resource.member_scope, &block) } else path_scope(parent_resource.member_scope, &block) end end end
namespace(name, deprecated_options = nil, as: DEFAULT, path: DEFAULT, shallow_path: DEFAULT, shallow_prefix: DEFAULT, **options, &block) Link
nested(&block) Link
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1754 def nested(&block) unless resource_scope? raise ArgumentError, "can't use nested outside resource(s) scope" end with_scope_level(:nested) do if shallow? && shallow_nesting_depth >= 1 shallow_scope do path_scope(parent_resource.nested_scope) do scope(**nested_options, &block) end end else path_scope(parent_resource.nested_scope) do scope(**nested_options, &block) end end end end
new(&block) Link
resource(*resources, concerns: nil, **options, &block) Link
有时,您会遇到客户端始终在不引用 ID 的情况下查找的资源。一个常见的例子是,/profile 始终显示当前登录用户的个人资料。在这种情况下,您可以使用单数资源来映射 /profile(而不是 /profile/:id)到 show 操作。
resource :profile
This creates six different routes in your application, all mapping to the Profiles controller (note that the controller is named after the plural)
GET /profile/new GET /profile GET /profile/edit PATCH/PUT /profile DELETE /profile POST /profile
If you want instances of a model to work with this resource via record identification (e.g. in form_with or redirect_to), you will need to call resolve
resource :profile resolve('Profile') { [:profile] } # Enables this to work with singular routes: form_with(model: @profile) {}
Options¶ ↑
Takes same options as resources
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1490 def resource(*resources, concerns: nil, **options, &block) if resources.grep(Hash).any? && (deprecated_options = resources.extract_options!) concerns = assign_deprecated_option(deprecated_options, :concerns, :resource) if deprecated_options.key?(:concerns) assign_deprecated_options(deprecated_options, options, :resource) end if apply_common_behavior_for(:resource, resources, concerns:, **options, &block) return self end with_scope_level(:resource) do options = apply_action_options :resource, options resource_scope(SingletonResource.new(resources.pop, api_only?, @scope[:shallow], **options)) do yield if block_given? concerns(*concerns) if concerns new do get :new end if parent_resource.actions.include?(:new) set_member_mappings_for_resource collection do post :create end if parent_resource.actions.include?(:create) end end self end
resources(*resources, concerns: nil, **options, &block) Link
In Rails, a resourceful route provides a mapping between HTTP verbs and URLs and controller actions. By convention, each action also maps to particular CRUD operations in a database. A single entry in the routing file, such as
resources :photos
creates seven different routes in your application, all mapping to the Photos controller
GET /photos GET /photos/new POST /photos GET /photos/:id GET /photos/:id/edit PATCH/PUT /photos/:id DELETE /photos/:id
Resources can also be nested infinitely by using this block syntax
resources :photos do resources :comments end
This generates the following comments routes
GET /photos/:photo_id/comments GET /photos/:photo_id/comments/new POST /photos/:photo_id/comments GET /photos/:photo_id/comments/:id GET /photos/:photo_id/comments/:id/edit PATCH/PUT /photos/:photo_id/comments/:id DELETE /photos/:photo_id/comments/:id
Options¶ ↑
Takes same options as match as well as
- :path_names
-
Allows you to change the segment component of the
editandnewactions. Actions not specified are not changed.
resources :posts, path_names: { new: "brand_new" }
The above example will now change /posts/new to /posts/brand_new.
- :path
-
Allows you to change the path prefix for the resource.
resources :posts, path: 'postings' The resource and all segments will now route to /postings instead of /posts.
- :only
-
Only generate routes for the given actions.
resources :cows, only: :show resources :cows, only: [:show, :index]
- :except
-
Generate all routes except for the given actions.
resources :cows, except: :show resources :cows, except: [:show, :index]
- :shallow
-
Generates shallow routes for nested resource(s). When placed on a parent resource, generates shallow routes for all nested resources.
resources :posts, shallow: true do
resources :comments
end
Is the same as:
resources :posts do
resources :comments, except: [:show, :edit, :update, :destroy]
end
resources :comments, only: [:show, :edit, :update, :destroy]
This allows URLs for resources that otherwise would be deeply nested such
as a comment on a blog post like `/posts/a-long-permalink/comments/1234`
to be shortened to just `/comments/1234`.
Set `shallow: false` on a child resource to ignore a parent's shallow
parameter.
- :shallow_path
-
Prefixes nested shallow routes with the specified path.
scope shallow_path: "sekret" do
resources :posts do
resources :comments, shallow: true
end
end
The `comments` resource here will have the following routes generated for
it:
post_comments GET /posts/:post_id/comments(.:format)
post_comments POST /posts/:post_id/comments(.:format)
new_post_comment GET /posts/:post_id/comments/new(.:format)
edit_comment GET /sekret/comments/:id/edit(.:format)
comment GET /sekret/comments/:id(.:format)
comment PATCH/PUT /sekret/comments/:id(.:format)
comment DELETE /sekret/comments/:id(.:format)
- :shallow_prefix
-
Prefixes nested shallow route names with specified prefix.
scope shallow_prefix: "sekret" do
resources :posts do
resources :comments, shallow: true
end
end
The `comments` resource here will have the following routes generated for
it:
post_comments GET /posts/:post_id/comments(.:format)
post_comments POST /posts/:post_id/comments(.:format)
new_post_comment GET /posts/:post_id/comments/new(.:format)
edit_sekret_comment GET /comments/:id/edit(.:format)
sekret_comment GET /comments/:id(.:format)
sekret_comment PATCH/PUT /comments/:id(.:format)
sekret_comment DELETE /comments/:id(.:format)
- :format
-
Allows you to specify the default value for optional
formatsegment or disable it by supplyingfalse. - :param
-
Allows you to override the default param name of
:idin the URL.
Examples¶ ↑
# routes call Admin::PostsController resources :posts, module: "admin" # resource actions are at /admin/posts. resources :posts, path: "admin/posts"
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1663 def resources(*resources, concerns: nil, **options, &block) if resources.grep(Hash).any? && (deprecated_options = resources.extract_options!) concerns = assign_deprecated_option(deprecated_options, :concerns, :resources) if deprecated_options.key?(:concerns) assign_deprecated_options(deprecated_options, options, :resources) end if apply_common_behavior_for(:resources, resources, concerns:, **options, &block) return self end with_scope_level(:resources) do options = apply_action_options :resources, options resource_scope(Resource.new(resources.pop, api_only?, @scope[:shallow], **options)) do yield if block_given? concerns(*concerns) if concerns collection do get :index if parent_resource.actions.include?(:index) post :create if parent_resource.actions.include?(:create) end new do get :new end if parent_resource.actions.include?(:new) set_member_mappings_for_resource end end self end
resources_path_names(options) Link
root(path, options = {}) Link
You can specify what Rails should route “/” to with the root method
root to: 'pages#main'
For options, see match, as root uses it internally.
You can also pass a string which will expand
root 'pages#main'
You should put the root route at the top of config/routes.rb, because this means it will be matched first. As this is the most popular route of most Rails applications, this is beneficial.
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1903 def root(path, options = {}) if path.is_a?(String) options[:to] = path elsif path.is_a?(Hash) && options.empty? options = path else raise ArgumentError, "must be called with a path and/or options" end if @scope.resources? with_scope_level(:root) do path_scope(parent_resource.path) do match_root_route(options) end end else match_root_route(options) end end
shallow() Link
shallow?() Link
实例私有方法
api_only?() Link
set_member_mappings_for_resource() Link
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 2108 def set_member_mappings_for_resource # :doc: member do get :edit if parent_resource.actions.include?(:edit) get :show if parent_resource.actions.include?(:show) if parent_resource.actions.include?(:update) patch :update put :update end delete :destroy if parent_resource.actions.include?(:destroy) end end