我可以拥有相同的 URL 但不同的动态细分吗?
Can I have the same URL, but different dynamic segments?
是否可以使用相同的 URL,但使用不同的动态细分?
我的问题是:我希望能够将对象 A
添加到对象 B
和 C
。所以我想要 2 Rails 条路线,A/new/:b_id
和 A/new/:c_id
。我试过了。
在我的 routes.rb:
controller :A do
get 'A/new/:b_id', to: 'A#new', as: :new_b_a
get 'A/new/:c_id', to: 'A#new', as: :new_c_a
end
问题是传递到新页面的值总是 params[:b_id]
! (我可以使用 params[:b_id]
从 URL 打印出值。)
所以我似乎不能拥有 2 条具有不同动态路段的相似路线..?如果是这样,我该怎么做?
路由系统的工作原理是尝试将当前路径从上到下匹配到每条已注册的路由。动态 :b_id
部分表示 "anything that goes here in the path will be passed as a parameter called :b_id
to the controller"。因此,向 "A/new/anything"
发出请求将始终匹配第一条路由,并且由于您将参数重命名为 :new_b_a
,这就是它在 params
哈希中的调用方式。
如果您真的想使用相同的路由,则需要传递一个额外的参数来指定要与之建立关系的 class,但我不建议这样做。它可能类似于 get 'A/new/:klass/:id'
,因此在控制器中您可以将参数匹配到所需的 classes:
def new
case params[:klass]
when 'B' then # do stuff
when 'C' then # do stuff
else raise "Invalid class: #{params[:klass]}"
end
end
更好的方法是使用 nested resources.
您总是会得到 :b_id
,因为 Rails 按照它们在您的文件中出现的顺序匹配路由。由于 B
ID 是一个与 C
ID 无法区分的整数,因此它无法知道您是否想要其中一个。
但是,因为您已经有了 B
和 C
,也许还需要创建、显示等,您可以 RESTfully 区分它们的路径,这就是Rails要你做。
# config/routes.rb
resources :bs do
resources :as
end
resources :cs do
resources :as
end
这将为您构建您手动创建的路径,但稍作调整:
/bs/:b_id/as/new
/cs/:c_id/as/new
如您所见,路径现在也以您要添加 A
的对象类型开头,因此 Rails 可以区分它们。为此生成的辅助方法看起来与您当前手动定义的辅助方法相同:
new_b_a_path(b)
new_c_a_path(c)
两条路径都会将您引导至 AsController
,然后您需要根据存在的参数查找正确的 B
或 C
:
# AsController#new
@parent = B.find(params[:b_id]) if params[:b_id]
@parent = C.find(params[:c_id]) if params[:c_id]
@a = parent.build_a # Assuming has_one or has_many from B and C to A
Rails 花了很长时间来开发一种特殊的方法来做这类事情。你总是可以潜入并以不同的方式去做,但最好的情况是你会浪费精力,最坏的情况是你会与框架作斗争。该框架不那么妥协,通常会获胜。
是否可以使用相同的 URL,但使用不同的动态细分?
我的问题是:我希望能够将对象 A
添加到对象 B
和 C
。所以我想要 2 Rails 条路线,A/new/:b_id
和 A/new/:c_id
。我试过了。
在我的 routes.rb:
controller :A do
get 'A/new/:b_id', to: 'A#new', as: :new_b_a
get 'A/new/:c_id', to: 'A#new', as: :new_c_a
end
问题是传递到新页面的值总是 params[:b_id]
! (我可以使用 params[:b_id]
从 URL 打印出值。)
所以我似乎不能拥有 2 条具有不同动态路段的相似路线..?如果是这样,我该怎么做?
路由系统的工作原理是尝试将当前路径从上到下匹配到每条已注册的路由。动态 :b_id
部分表示 "anything that goes here in the path will be passed as a parameter called :b_id
to the controller"。因此,向 "A/new/anything"
发出请求将始终匹配第一条路由,并且由于您将参数重命名为 :new_b_a
,这就是它在 params
哈希中的调用方式。
如果您真的想使用相同的路由,则需要传递一个额外的参数来指定要与之建立关系的 class,但我不建议这样做。它可能类似于 get 'A/new/:klass/:id'
,因此在控制器中您可以将参数匹配到所需的 classes:
def new
case params[:klass]
when 'B' then # do stuff
when 'C' then # do stuff
else raise "Invalid class: #{params[:klass]}"
end
end
更好的方法是使用 nested resources.
您总是会得到 :b_id
,因为 Rails 按照它们在您的文件中出现的顺序匹配路由。由于 B
ID 是一个与 C
ID 无法区分的整数,因此它无法知道您是否想要其中一个。
但是,因为您已经有了 B
和 C
,也许还需要创建、显示等,您可以 RESTfully 区分它们的路径,这就是Rails要你做。
# config/routes.rb
resources :bs do
resources :as
end
resources :cs do
resources :as
end
这将为您构建您手动创建的路径,但稍作调整:
/bs/:b_id/as/new
/cs/:c_id/as/new
如您所见,路径现在也以您要添加 A
的对象类型开头,因此 Rails 可以区分它们。为此生成的辅助方法看起来与您当前手动定义的辅助方法相同:
new_b_a_path(b)
new_c_a_path(c)
两条路径都会将您引导至 AsController
,然后您需要根据存在的参数查找正确的 B
或 C
:
# AsController#new
@parent = B.find(params[:b_id]) if params[:b_id]
@parent = C.find(params[:c_id]) if params[:c_id]
@a = parent.build_a # Assuming has_one or has_many from B and C to A
Rails 花了很长时间来开发一种特殊的方法来做这类事情。你总是可以潜入并以不同的方式去做,但最好的情况是你会浪费精力,最坏的情况是你会与框架作斗争。该框架不那么妥协,通常会获胜。