一个视图中的多个控制器(ruby on rails MVC)

时间:2012-11-07 19:47:13

标签: ruby-on-rails controller render params

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

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

Inside 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

Inside UsersController

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

在app / views / users / 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)在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中使用此版本的create动作,

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

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

2 个答案:

答案 0 :(得分:3)

  1. 从技术上讲,这个术语有点令人困惑。默认情况下,控制器中的每个方法都对应一个类似命名的视图文件,因此最好将问题说成“渲染不是默认视图的视图是不错的做法?”当然,答案取决于它。这是一种常用于干扰控制器代码的技术,如果它有好处,在你的应用程序中,我当然会使用它。实际上,控制器代码由createupdate方法中的Rails uses it中的默认资源支架生成。我认为你可以说Rails核心中的任何东西,如果不是最佳实践,至少在理智的范围内。

  2. 话虽如此,但可能有改进的机会。处理相同事物的常用方法是将创建和更新请求路由到同一个控制器操作并使用相同的控制器视图。如果这不可行,至少可以确保您不需要重新定义变量。来自official documentation

  3.   

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

    1. 你不应该这样做......不是在这种情况下,或者我能想到的任何其他情况。任何时候你在Rails中看到类似超级hackey的东西都表明某些东西可能不太正确,并且可能有更好的方法来处理同样的事情。
    2. 奖励:如果您需要去一个已经负责设置自己的地方,并且您不需要访问任何范围内的变量,重定向可能是更好的选择。这样,您就不需要在多个位置重新描述控制器逻辑。以下是您发布的代码中的示例:

          # 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
      

答案 1 :(得分:0)

我想补充一点,我认为为什么教程作者为Create Microposts操作实现了较少DRY解决方案的理由是因为如果使用redirect_to而不是render,那么它们会丢失表单的flash错误。 / p>

我不确定是否有更多DRY解决方案可以保持闪存错误。