2010-02-25 130 views
4

这发生在我身上好几次了,我还没有找到一个可接受的解决方案。在Ruby on Rails中运行另一个控制器操作

我在一个网站的主页上有一个窗体,它指向另一个控制器,它实际上处理数据。当表单提交成功后,另一个控制器会发送回到主页,并带有一个不错的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

这是从正常的香草栏形式不同吗?

if(valid) 
flash = ... 
redirect_to :home 
else 
rerender form with error messages & submitted values 
end 
+0

不同之处在于,渲染已包含在主页操作中的表单需要很多控制器逻辑。 – EmFi 2010-02-25 05:26:04

+0

重新渲染表格丢失了家庭控制器操作中的大约25行代码。 – Pablo 2010-02-25 05:26:53

1

多少时形式呈现并请求重定向到默认的行动之间的更改主页的休息吗?

如果答案不是很多,那么您应该考虑使用remote_form_for,并且只更新成功时的通知区域或更新失败时验证错误的表单。

如果这不符合您的要求,可以将主页操作中的所有重复逻辑移动到ApplicationController类中定义的方法,并将其作为主页操作的before_filter的一部分进行调用,你的形式。 N.B:以这种方式做事需要您设置实例变量,在过滤器中设置的局部变量不会持续到动作。

+0

这可能是一个可能的解决方案。谢谢。 – Pablo 2010-02-25 05:27:33

+0

@J。巴勃罗费尔南德斯:我编辑了我的解决方案,以包含另一种方式。 – EmFi 2010-02-25 05:29:38

1

我以前遇到过这个问题。我来自CakePHP,验证错误存储在会话中,并在请求之间持续存在。 Rails在默认情况下不会采用这种方式,这就让您决定如何处理错误。

正如你明显也读过的那样,将错误放入会话并进行重定向通常不会在Rails世界中建议。正如你所说,Rails的方式似乎只是在不做重定向的情况下渲染另一个动作。当我第一次尝试时,我注意到我被迫重复了很多代码,以便设置第二个动作来呈现第一个动作的视图。

与任何类型的代码重复一样,解决方案是将重复的代码移动到单独的方法中,然后从两个操作中调用该方法。干净的方法是使用before_filter来运行这两个操作的代码。

+0

当你在控制器间进行交互时,如何将其移动到单独的方法,就像我现在更新的示例中那样?使用before_filter意味着要进行额外的不准确的查询以防万一,不是吗? – Pablo 2010-02-27 10:43:03

+0

不知道我理解你的代码......在你的'Comments#create'动作中,这个'@ reason'变量是从哪里冒出来的?你突然想要保存一些甚至不存在的东西。此外,“如果不是@ post”块不会做你想要的。您需要在提取帖子的行上解救'ActiveRecord :: RecordNotFound'。 – 2010-02-27 22:23:24

0

我同意这里的其他海报 - 如果您有类似的代码,那么重构为每个控制器操作所调用的常用方法是非常重要的。

如果控制器在多个控制器中很常见,则应用控制器是最好的选择。

或者,您可以制作一个通用控制器类,即两个控制器都继承自 - 且仅包含该辅助方法。除非您可能会分享其他方法,否则我不建议您这样做。

相关问题