我有一个has_many
条的Foo资源。我使用嵌套资源进行有限数量的操作,但是我更喜欢保持我对条形图的路由较浅。有两种方法可以导航到Bar对象的编辑视图 - 从包含foo
的嵌套路径,或从不在{{1}内嵌套的较浅bar
路径导航}。例如,用户可能会点击foo
页面上的修改按钮;或者来自/foos/[:foo_id]/bar/[:bar_id]
。
在第一种情况下,我希望控制器在更新记录后将用户重定向回父foo页面:/bars/[:bar_id]
。在第二种情况下,我希望它重定向到/foos/[:foo_id]
:bars
的索引视图。我相信我需要在/bars
控制器中的#edit
操作中使用某种条件,该操作将告诉Rails执行bars
后的位置。
#update
# config/routes.rb
resources :foos do
resources :bars, only: [:new, :edit]
end
resources :bars
# bin/rake routes:
foo_bars POST /foos/:foo_id/bars(.:format) bars#create
new_foo_bar GET /foos/:foo_id/bars/new(.:format) bars#new
edit_foo_bar GET /foos/:foo_id/bars/:id/edit(.:format) bars#edit
bars GET /bars(.:format) bars#index
POST /bars(.:format) bars#create
new_bar GET /bars/new(.:format) bars#new
edit_bar GET /bars/:id/edit(.:format) bars#edit
bar GET /bars/:id(.:format) bars#show
PATCH /bars/:id(.:format) bars#update
PUT /bars/:id(.:format) bars#update
DELETE /bars/:id(.:format) bars#destroy
的控制器:
bars
我尝试更改# app/controllers/bar_controller.rb
def edit
@bar = bar.find(params[:id])
@foo = @bar.foo
end
def update
@bar = bar.find(params[:id])
@foo = @bar.foo
respond_to do |format|
if @bar.update_attributes(bar_params)
format.html { redirect_to @foo, notice: "bar successfully updated" }
else
format.html { render action: "edit" }
end
end
end
操作中的redirect_to @foo
行,因此有条件逻辑可以为#update
切换@foo
,具体取决于@bars
{1}}已采取行动。我尝试过以下内容来测试调用#edit
操作时是否存在params[:foo]
,为重定向设置实例变量。
#edit
这不起作用。 Rails陈述def edit
if params[:foo]
@redirect_page = @foo
else
@redirect_page = @bars
end
@bar = bar.find(params[:id])
@foo = @bar.foo
end
def update
# code omitted...
format.html { redirect_to @redirect_page, notice: "bar successfully updated" }
# code omitted...
end
。我还在cannot redirect to nil!
操作中使用基于URI(request.referer).path
的测试尝试了一些操作,但没有成功。
我还不完全清楚Rails魔法是如何在控制器中发生的。我相信#edit
操作是定义重定向的条件(或通过#edit
操作中调用的方法)的适当位置,因为控制器将在其中执行操作。见"传入的请求并知道它来自何处。但我无法理解捕获这些信息,并将其传递给#edit
。感谢任何指导。
答案 0 :(得分:2)
在您的修改表单中,添加hidden_field_tag
:
<%= hidden_field_tag "route", request.env['PATH_INFO'] %>
然后在您的控制器中,您可以拥有if
语句,并根据redirect_to
的内容使用params[:route]
。
答案 1 :(得分:0)
我明白了。使用request.env['PATH_INFO]
的params [:route]方法对我来说并不适用,因为&#39; PATH_INFO&#39;表单中的变量提供了bars#update
操作的路径,而不是启动bars#edit
操作的路径。
点击&#34;编辑&#34;来自/foos/[:id]
的父foo页面,params散列是:
>> params
=> {"controller"=>"bars", "action"=>"edit", "foo_id"=>"3786", "id"=>"16"}
首次访问表单时params[:route]
没有值 - 隐藏字段仅在点击&#34后更新到params哈希值;更新&#34;在编辑表格中:
>> params[:route]
=> "/foos/3786/bars/16/edit"
这可行,但需要构建逻辑来解析路由才能重定向到/foos/[:foo_id]
事实证明,使用Rails flash
方法存储重定向到源页面的路径更为简单。我通过在BarsController中调用自定义方法set_redirect_path
并在bars#edit
中调用它来完成此操作。这将为闪存中的源设置一个值,该值在bars#update
中可用。也许有更好/更传统的方式来实现这一目标,但这似乎是一种干净而简单的方式来做我想要的。
# app/controllers/bars_controller.rb
def edit
set_redirect_path
@bar = bar.find(params[:id])
@foo = @bar.foo
end
def update
@bar = bar.find(params[:id])
@foo = @bar.foo
respond_to do |format|
if @bar.update_attributes(bar_params)
format.html { redirect_to flash[:source], notice: "bar successfully updated" }
format.xml { head :ok }
else
format.html { render action: "edit" }
format.xml { render xml: @bar.errors, status: :unprocessable_entity }
end
end
end
private
def set_redirect_path
flash[:source] = URI(request.referer).path
end
这种方法的一个优点是我现在可以摆脱共享部分app/views/bars/_list.html.haml
中的条件逻辑,这是确定是否单击&#34;编辑&#34;按钮应该路由到edit_foo_bar_path
或edit_bar_path
(即如果存在@foo
则选择前者)。因此,我可以删除嵌套资源:edit
的{{1}}。由于Flash捕获请求的传入源并将其存储在:bars
操作中以供参考,因此所有编辑请求都可以使用相同的#update
,无论它们来自何处。更新后,Rails会将用户重定向到他们发起edit_bar_path
操作的位置。