Rails 3从另一个控制器渲染操作

26

我需要渲染另一个控制器的操作 <%= render "controller/index" %>,但是出现了以下错误:

在视图路径“/path_to/app/views”中找不到局部文件 controller/index(带有 {:formats=>[:html], :locale=>[:en, :en], :handlers=>[:rjs, :rhtml, :rxml, :erb, :builder]})

我该如何将另一个控制器的操作渲染到视图中,而不向客户端发送重定向?我已经尝试了以下方法:

<%=render :action => "index", :controller=>"controller" %>

但似乎它不起作用。


你在views/your_controller/目录下有一个index.html.erb文件吗? - Andrei S
1
为什么不使用重定向到正确的控制器操作? - Daniel X Moore
1
因为这些操作的逻辑可能完全不同,唯一共同点就是视图。 - Arsen7
5个回答

30

尝试渲染模板:

<%= render :template => "controller/index" %> 

或文件:

<%= render :template => "#{Rails.root}/app/controllers/controller/index" %> 

我认为您应该通过控制器进行渲染,因为这样更方便:

def your_action
  ...
  render :action => :index
end

我尝试使用render :template,但它渲染的是HTML,我需要渲染index方法,因为index方法获取了一些在该视图中所需的来自数据库的数据。 - Mihai
fl00r 是正确的,最好从控制器内部处理这个问题。请注意,如果找不到 controller/index,则有一个内置的回退机制,它会渲染 application/index。因此,如果有需要从不同控制器呈现的页面(而不是局部视图),请将它们放在 app/views/application 下。 - Yorick Sijsling

21

这对我很有效:

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

然后,按照调用方式:

render :text => renderActionInOtherController(OtherController,:otherAction,params)

基本上它是通过对另一个类进行修改,覆盖其"params"方法并返回结果来实现的。

如果你正在使用 Rails 4:

def renderActionInOtherController(controller,action,params)
    c = controller.new
    c.params = params
    c.dispatch(action, request)
    c.response.body
end

这对我也起作用了,但我需要添加 c.process_action(action) 来触发我的 before_actions - Emerson
2
太棒了,这是一个很好的技巧。非常感谢! - Abhinav Pandey

20

从Rails指南的页面

对于Rails初学者来说,使用带有 :action 参数的 render 经常会导致混淆。指定的 action 用于确定要呈现哪个视图,但Rails不会运行控制器中该动作的任何代码。在调用 render 之前,必须在当前操作中设置视图所需的任何实例变量。

简而言之,您不能呈现另一个操作,只能呈现另一个模板。如果您无法以其他方式结构化代码,则可以获取共享代码并将其移动到应用程序控制器中的方法中。您也可以尝试采用类似以下方案:

# This is a hack, I'm not even sure that it will work and it will probably
# mess up your filters (like ignore them).
other_controller = OtherController.new
other_controller.request = @_request
other_controller.some_action

0

如果你不仅仅想渲染另一个控制器(/model)的视图,而是要调用它的操作(方法),那么请更多地考虑 Ruby 的生活方式 - 把这个方法放到一个模块中,并在需要它的控制器中包含它。

我认为这比某种方式触及其他控制器要少一些“神秘感”。

module StandardActions
    def show_user_homepage(local_params=params)
        #something finding 
        #something to check
        render :"homepage/show" 
    def
end

class AddressesController < ApplicationController
    include StandardActions

    def update
        # update address
        if ok
            show_user_homepage(id: user_id)
        else
            #errorthings
            render :edit #(eg.)
        end
    end         
end

class HobbiesController  < ApplicationController
    include StandardActions

    def update      
        # update hobby
        if ok
            show_user_homepage(id: user_id)
        else
            #errorthings
            render :edit #(eg.)
        end
    end         
end

0
渲染另一个控制器的部分视图没有问题。 那么为什么不将原始操作视图移动到一个部分视图,并在需要的地方渲染这个部分视图呢:
将 app/views/controller_a/index.html.erb 移动到 app/views/controller_a/_index.html.erb。

app/views/controller_a/index.html.erb:

<%= render partial: 'index' %>

app/view/controller_b/some_action.html.erb:

<%= render partial: 'controller_a/index' %>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接