【问题标题】:Calling a method from a controller in Rails?从 Rails 中的控制器调用方法?
【发布时间】:2014-07-29 01:21:08
【问题描述】:

我是一名 Rails 初学者,这个简单的问题让我很困惑。 在每个页面上,我都想要我的应用程序中所有可用页面的列表。所以在 layouts/application.html.erb 我有以下代码:

<ul>
<!-- This loop prints out links to all the pages -->
<% @pages = Page.all %>
<% @pages.each do |page| %>
<li><%= link_to page.name, page_path(page) %></li>
<% end %>

此代码确实有效,但我对它不满意,因为它违反了 MVC 原则。实际上,我不想使用 查询数据库,而是想调用 PagesController 中的 getpages 方法,如下所示:

def getpages
    @pages = Page.all
end

我的第一反应是用 替换 ,但没有成功。 我相信这个问题与路由有关,任何人都可以启发我。

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    您可以通过多种方式完成此操作。我会尝试总结它们,但最简单的方法是在控制器上使用 before_filter

    考虑到你的方法在控制器中被命名为get_pages,只需写:

    class SomeController < ApplicationController
      before_filter :get_pages
    
      def get_pages
        @pages = Page.all
      end
    end
    

    然后,在您看来,您将能够在所有控制器操作中以 @pages 的身份访问它。

    【讨论】:

    • 你还没有说他应该如何访问它,这是他遇到问题的部分。
    【解决方案2】:

    如果是这样,只需在控制器中添加以下代码即可

    def youraction
      @pages = Page.all
    end
    

    这将使全局变量@pages 在您的视图中可用。直接调用为@pages。

    【讨论】:

    • 不,你没有很好地阅读这个问题。 OP 想要多个页面上的页面列表。
    【解决方案3】:

    首先,让我说你的方法不是错误恕我直言。引入一个只是 Page.all 别名的额外方法并不是真正需要的,也不是真正的改进。

    但肯定有更好的方法。

    我会按如下方式解决这个问题:在ApplicationController 我会添加方法

    def get_all_pages
      @pages ||= get_all_pages
    end
    

    这将确保任何控制器都知道该方法。

    然后,如果您确定,每个页面都需要它,您可以在您的ApplicationController 中添加一个before_filter,但一般来说,我更喜欢将它写在控制器本身中。

    例如

    class IdeasController < ApplicationController
    
      before_action :get_all_pages
    
      ... the rest of your controller ... 
    
    end
    

    另外,我会将您的页面列表提取到部分中,存储在 app/views/shared/_pages_list.html.erbapp/views/pages/_pages_list.html.erb 下,然后在您的 application.html.erb 中调用以呈现部分。

    我们调用的方法设置了实例变量@pages,它将在视图中可用,所以你的部分想:

    <ul>
      <% @pages.each do |page| %>
        <li><%= link_to page.name, page_path(page) %></li>
      <% end %>
    </ul>
    

    最后,为了完整起见,让我回答一下如何使控制器方法在视图中可用。在控制器中写

    def get_pages
      # ..do something
    end
    helper_method :get_pages
    

    这将使get_pages 方法在视图中可用,但仅适用于负责加载/呈现该视图的控制器。因此,如果您希望所有视图都使用它,请在 ApplicationController 中定义它。例如。这是我们在定义current_user方法时通常会做的事情。

    进一步的改进/替代方案

    • 如果您开始获取更多代码,请将与页面列表获取和渲染相关的代码提取到单独的模块中,并将其包含到您的 ApplicationController 中。这使您的ApplicationController 更具可读性。

      • 注意:这正是引入 concerns 的目的,因此如果您在 rails 4 上,您可以使用它
    • Page 是它自己的资源,因此您始终可以创建一个单独的PagesController 并确保它负责呈现列表,并使用 ajax 在需要它的页面上获取。这是一个非常好的解决方案,但也需要更多的工作(矫枉过正?)。但结构非常好。

    • 这个问题,页面上有不同的区域,每个区域都应该有自己的控制器-模型-视图,这正是cells gem gem 以非常干净的方式解决的问题。在我链接的页面上有一个非常好的渲染购物车示例,因此您可以随时查看。

    【讨论】:

      【解决方案4】:

      您可以像这样使用helper method

      #app/helpers/application_helper.rb
      Class ApplicationHelper
         def pages
             Page.all
         end
      end
      

      助手在您的视图中可用,因此您可以这样做:

      #app/views/application/index.html.erb
      <% pages.each do |page| %>
         <%= page.title %>
      <% end %>
      

      【讨论】:

        【解决方案5】:

        另一种方法是使用异步调用来加载PagesController#index 的结果并将其显示在您的应用程序布局中。

        $.ajax("<%= pages_path %>").done(function(html) {
            $("#pages-list").html(html);
        });
        

        要实现这一点,如果request.xhr? 返回true,您可以使用layout: false 渲染PagesController#index

        【讨论】:

        • 为什么投反对票?这实际上是一个非常好的方法。至少你只在一个地方定义了 pages 并真正重用它。
        • 是的,不赞成投票至少应该是出于恕我直言。
        • 我没有投反对票,但问题来自 Rails 初学者,与 ajax 无关。答案似乎与问题几乎完全无关——他们唯一的共同点是引用pages
        猜你喜欢
        • 2017-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-13
        • 1970-01-01
        • 2017-02-22
        相关资源
        最近更新 更多