当我查看 Rails Controller 的示例时,我通常会看到如下内容:
class WidgetController < ActionController::Base
def new
@widget = Widget.new
end
def create
@widget = Widget.new(params[:id])
if @widget.save
redirect_to @widget
else
render 'new'
end
end
end
这可行,但有几个问题:
路线
如果我将小部件添加到我的routes.rb 文件中:
Example::Application.routes.draw do
resources :widgets
end
GET/widgets/new
将路由到 new
,POST/widgets
将路由到 create
。
如果用户在新的小部件页面上输入不正确的信息并提交,他们的浏览器将显示带有 /widgets
的 URL,但将呈现新模板。如果用户为页面添加书签并稍后返回或刷新页面,则将调用索引操作而不是新操作,这不是用户所期望的。如果没有索引操作或者用户没有查看它的权限,则响应将为 404。
代码重复
作为一个人为的例子,假设我的新方法中有一些棘手的逻辑:
def new
@widget = Widget.new
do_something_tricky()
end
使用当前方法,我会在 new
和 create
中复制该逻辑。我可以从 create
调用 new
,但随后我必须修改 new
来检查 @widget
是否为定义:
def new
@widget ||= Widget.new
do_something_tricky()
end
另外,这感觉不对,因为它降低了 Controller 操作的正交性。
做什么?
那么解决这个问题的Rails 方式是什么呢?我应该重定向到 new
而不是渲染新模板吗?我应该在 create
内部调用 new
吗?我应该忍受它吗?有更好的办法吗?
最佳答案
我不认为这在“rails 方式”中是一个问题,并且没有内置功能可以在不弄脏您的手的情况下允许这样做。当用户为刚刚提交且有错误的表单添加书签时,他们期望什么?用户不知道更多,他们不应该为失败的表单添加书签。
我认为重定向到 new_widget_path
是最干净的解决方案。但是,您应该保留错误并将其显示在表单上。为此,我建议您将参数保留在 session 中(我希望它比序列化的 Widget 对象小)。
def new
@widget = widget_from_session || Widget.new
end
def widget_from_session
Widget.new(session.delete(:widget_params)) if session[:widget_params].present?
end
private :widget_from_session
# Before the redirect
session[:widget_params] = params
代码是不言自明的,只有当 widget_from_session
返回 nil 时才会调用 Widget.new
,此时 session[:widget_params] 存在。对哈希调用 delete
将返回删除的值并将其从原始哈希中删除。
更新选项 2 使用ajax提交表单怎么样?您的 Controller 可以受益于:
respond_to :html, :json
...
def create
@widget = Widget.new params[:widget]
@widget
respond_with @widget, location: nil
end
根据响应代码(由 Rails 设置:201 Created 或 422 Unprocessable Entity),您可以显示错误(验证失败时在响应正文中可用)或将用户重定向到 @widget
这就是 StackOverflow 的做法:https://stackoverflow.com/questions/ask 。他们异步提交表单。
关于ruby-on-rails - Ruby on Rails Controller 设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15193081/