这次发生在我身上好几次,我还没有找到一个可以接受的解决方案。
我在网站的主页中有一个表单,该表单指向另一个实际负责处理数据的控制器。当表单成功提交后,另一个控制器会将一条漂亮的flash [:notice]消息发送回主页,这就是它的结尾。
当出现验证问题时,它就成了一个问题。我想要做的是显示带有验证错误的表单的主页。通常提到的天真解决方案是你可以渲染另一个模板,但显示主页不仅仅是渲染模板,它还有很多功能。渲染该模板的唯一方法是在其他控制器操作中复制和粘贴功能,或者从控制器中取出所有功能,这也不是很好
有更好的解决方案吗?
更新:我理解有人说控制器操作应该更小并调用另一种方法,但在实践中,我看不到如何实现它。我将在我做过的网站上发布一个真实的例子。
有两种型号和控制器:帖子和评论。帖子有很多原因。帖子以这种方式显示:
def index
set_posts # sets @posts
end
def show
@post = Post.find_by_slug(params[:id])
@comment = Comment.new
if not @post
flash[:error] = "'#{params[:id]}' does't exist"
set_posts
render :action => :index, :status => :not_found
end
end
private
def set_posts
@posts = Posts.get_all_public_posts
end
评论控制器只有一个创建动作:
def create
@comment = Comment.new(params[:comment])
@comment.post = Post.find_by_slug params['post_id']
if not @comment.post
# Now what?
# We should here call PostsController.set_posts and render views/posts/index
end
if @reason.save
flash[:notice] = 'Thank you for your message.'
redirect_to(@reason.item)
else
# Now what?
# We should here call PostsController.show without overriding the @comment
end
end
端
“现在怎样?”部件是我没有很好的解决方案。
答案 0 :(得分:1)
在呈现表单并将请求重定向到默认操作时,主页的其余部分会发生多少变化?
如果答案不是很多,那么您应该考虑使用remote_form_for并仅在成功或表单上更新通知区域,并在失败时更新验证错误。
如果这不符合您的喜好,您可以将主页操作中的所有重复逻辑移动到ApplicationController类中定义的方法,并将其作为主页操作上的before_filter的一部分以及处理您的操作的操作调用形成。 N.B :这样做会要求你设置实例变量,过滤器中设置的局部变量在动作之前不会持续存在。
答案 1 :(得分:1)
之前我遇到过这个问题。我来自CakePHP,其中验证错误存储在会话中并在请求之间保持不变。默认情况下,Rails不会以这种方式运行,这使您决定如何处理错误。
正如您显然也读过的那样,将错误放入会话并进行重定向通常不建议在Rails世界中使用。正如你所说,Rails的方式似乎是简单地渲染另一个动作而不进行重定向。当我第一次尝试时,我注意到我被迫复制了大量代码,以便设置第二个动作来渲染第一个动作的视图。
与任何类型的代码重复一样,解决方案是将重复的代码移动到单独的方法中,然后从这两个操作中调用该方法。干净的方法是使用before_filter
运行两个操作的代码。
答案 2 :(得分:0)
这与普通的香草护栏有何不同?
if(valid)
flash = ...
redirect_to :home
else
rerender form with error messages & submitted values
end
答案 3 :(得分:0)
我同意这里的其他海报 - 如果你有类似的代码,那么重构为每个控制器动作所调用的公共方法。
应用程序控制器是放置它的最佳位置,如果它在多个控制器中是通用的。
或者,你可以创建一个两个控制器继承的公共控制器类 - 并且只包含该辅助方法。除非您可能也分享其他方法,否则我不建议这样做。