使用resources :users时,Rails如何区分GET /users/:id与GET /users/new路由?
理解Rails中
resources :users如何区分GET /users/:id和GET /users/new路由 这个问题的核心在于Rails路由的匹配优先级规则,以及resources方法生成路由的顺序设计,我来一步步拆解给你看:
1. 路由匹配的核心规则:先定义先匹配
Rails的路由系统是按照路由定义的从上到下的顺序进行匹配的——只要请求路径匹配到某条路由规则,就会立即使用这条路由,不会再往下检查后续规则。
这就意味着,如果GET /users/:id(对应show动作)的定义在GET /users/new(对应new动作)之前,那么当你请求/users/new时,Rails会把new当成:id的参数值,错误地路由到UsersController#show动作。
2. resources方法的路由生成顺序设计
Rails的resources方法早就考虑到了这个冲突问题,所以它生成RESTful路由时,会特意把带有固定后缀的路由(比如new、edit)放在带动态参数的路由(比如show)前面。
以resources :users为例,它生成的GET路由顺序是:
- 先生成
GET /users/new(对应new动作) - 再生成
GET /users/:id(对应show动作)
这样当请求/users/new时,会先匹配到new的路由规则,不会被误判为show路由的动态参数。
3. 结合你提供的源码片段看内部逻辑
你贴的resources方法片段里:
apply_common_behavior_for(:resources, resources, options, &block)会先处理一些通用的资源路由初始化逻辑(比如检查是否嵌套、处理命名空间等)- 进入
with_scope_level(:resources)作用域后,apply_action_options options会处理动作相关的配置,之后Rails会按照固定顺序逐个生成所有RESTful路由:# 大致的生成顺序(简化版) map.index # GET /users map.new # GET /users/new map.create # POST /users map.show # GET /users/:id map.edit # GET /users/:id/edit map.update # PATCH/PUT /users/:id map.destroy # DELETE /users/:id
正是这个顺序保证了new路由不会被show路由覆盖。
4. 验证这个逻辑的小实验
如果你手动修改路由顺序,比如在routes.rb里写:
get '/users/:id', to: 'users#show' get '/users/new', to: 'users#new'
此时请求/users/new会被路由到UsersController#show,且params[:id]的值是"new"——这也反向验证了Rails默认生成顺序的合理性。
内容的提问来源于stack exchange,提问作者Mahmoud Sayed
相关产品推荐
相关产品推荐

