2012-11-07 91 views
3

嘿,我需要你们宝贵的帮助。在Ruby on Rails tutorial,在第10章,作者在一个视图中有2个控制器。我构建了一个类似的应用程序,其中我在一个视图中也有2个控制器,但是,当我呈现属于第二个控制器的方法时,从第一个控制器出现问题。 (在教程中,作者没有在其他控制器的操作中使用任何参数)在一个视图中的多个控制器(ruby on rails MVC)

更具体地说,我有2个控制器:UsersController和MicropostsController。另外,在用户的show.html.haml页面中,我使用两个控制器:UsersController来显示用户的micropost和MicropostsController,以便用户创建一个新的微博。

内MicropostsController:

def create 
    @micropost = current_user.microposts.build(params[:micropost]) 
    if @micropost.save 
    flash[:success] = "Micropost created!" 
    redirect_to user_path(current_user) 
    else 
    #render text: renderActionInOtherController(UsersController,:show, {:id => 1}) 
    @user = User.find(current_user) 
    @microposts = @user.microposts.paginate(page: params[:page]) 
    render 'users/show' 
    end 
end 

内UsersController

def show 
    @user = User.find(params[:id]) 
    @microposts = @user.microposts.paginate(page: params[:page]) 
    @micropost = current_user.microposts.build if signed_in? 
end 

在应用程序/视图/用户/ show.html.haml

- provide(:title, @user.name) 
.users_page 
    .row 
    %aside.span4 
     - if !signed_in? 
     %section 
      %h1 
      = gravatar_for @user 
      = @user.name 
     - else 
     %section 
      = render 'shared/user_info' 
     %section 
      = render 'shared/micropost_form' 

    .span8 
     - if @user.microposts.any? 
     %h3 Microposts (#{@user.microposts.count}) 
     %ol.microposts 
      = render @microposts 
     = will_paginate @microposts 

所以基本上我的问题总结如下:

1)在一个视图中有多个控制器是一个好习惯吗?我在网上发现了矛盾的答案。 (实际上,我甚至不确定这段代码是否仍然是RESTful)

2)如果1是(或者至少这不是一个坏习惯)我能否以更高效的方式实现相同的功能?因为我看到它的方式,每次我从另一个控制器渲染动作,我都必须重新定义变量。

3)在stackoverflow中发现一个similar主题,其中一个人提议使用此方法(由于我是RoR中的新成员,因此我不明白它的作用)。

def renderActionInOtherController(controller,action,params) 
    controller.class_eval{ 
    def params=(params); @params = params end 
    def params; @params end 
    } 
    c = controller.new 
    c.request = @_request 
    c.response = @_response 
    c.params = params 
    c.send(action) 
    c.response.body 
end 

如果我使用这个版本里面创建MicropostsController行动,

def create 
    @micropost = current_user.microposts.build(params[:micropost]) 
    if @micropost.save 
    flash[:success] = "Micropost created!" 
    redirect_to user_path(current_user) 
    else 
    render text: renderActionInOtherController(UsersController,:show, {:id => 1}) 
    #@user = User.find(current_user) 
    #@microposts = @user.microposts.paginate(page: params[:page]) 
    #render 'users/show' 
    end 
end 

时,我打按钮后,我得到在浏览器中完全没有。此外,当我尝试查看用户/ 1页时,出现以下错误(!!):

undefined method `[]' for nil:NilClass 

任何帮助都将非常有价值!如果您需要任何其他信息,请通知我!

回答

4
  1. 从技术上讲,这个术语有点混淆。默认情况下,控制器中的每个方法都对应一个类似命名的视图文件,所以最好将问题改为“渲染不是默认视图的视图是否是好习惯?”答案当然要看。这是一种常用于干掉控制器代码的技术,如果它有优势,在你的应用程序中,我肯定会使用它。实际上,由默认资源脚手架生成的控制器代码在Rails uses it中的createupdate方法中。我认为你可以说Rails核心中的任何东西,如果不是最佳实践,至少在理智的范围内。

  2. 说到这里,可能会有改进的机会。处理同样事情的常见方法是将创建和更新请求路由到相同的控制器操作并使用相同的控制器视图。如果这是不可行的,至少可以保证你不需要重新定义变量。从official documentation

使用渲染:行动是混乱的为Rails 新人频繁的来源。指定的操作用于确定要渲染的视图,但Rails不会在 控制器中运行该操作的任何代码。调用render之前,必须在当前操作中设置视图中需要的任何实例变量 。

  1. 你不应该需要做的是...不是在这种情况下,或其他任何一个,我能想到的。任何时候当你看到Rails这样的超级黑客时,都是一种迹象表明某种东西可能不太正确,并且可能有更好的方法来处理同样的事情。

红利:如果您需要去某个已经负责设置自己的地方,并且您不需要访问任何范围变量,那么重定向可能是更好的选择。这样,您不需要在多个地方重新描述您的控制器逻辑。下面是从您发布的代码示例:

# inefficient and not DRY 
    @user = User.find(current_user) 
    @microposts = @user.microposts.paginate(page: params[:page]) 
    render 'users/show' 

    # does the same thing as above (in this case) 
    redirect_to users_path 
0

我只想补充一点,我相信,为什么教程作者实施的少干的解决方案,以创建微柱行动的理由是,因为如果一个使用redirect_to的,而不是渲染,然后他们失去了形式的Flash错误。

我不确定是否有更多DRY解决方案来维护表单Flash错误。

相关问题