[英]Calling a method from a controller in Rails?
I am a rails beginner and this simple question is really perplexing me. 我是铁轨初学者,这个简单的问题让我很困惑。 On every page, I want a list of all available pages in my app. 在每个页面上,我都想要一个包含我应用中所有可用页面的列表。 So in layouts/application.html.erb I have the following code: 所以在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 %>
This code DOES work, however I am not satisfied with it because it goes against MVC principles. 这段代码有效,但我对它不满意,因为它违背了MVC原则。 Really instead of querying the database with <% @pages = Page.all %>, I instead want to call the getpages method in the PagesController, which looks like this: 真的不是用<%@pages = Page.all%>查询数据库,而是想在PagesController中调用getpages方法,如下所示:
def getpages
@pages = Page.all
end
My first instinct was to replace <% @pages = Page.all %> with <% PagesController.getpages %>, which was unsuccessful. 我的第一直觉是用<%PagesController.getpages%>替换<%@pages = Page.all%>,这是不成功的。 I am confident this problem has something to do with routing, could anyone enlighten me. 我相信这个问题与路由有关,任何人都可以启发我。
There are several ways you accomplish this. 有几种方法可以实现这一目标。 I'll try to sum them up, but the easiest one is by using a before_filter
on your controller. 我会尝试总结它们,但最简单的方法是在控制器上使用before_filter
。
Considering your method is named get_pages
in the controller, just write: 考虑到你的方法在控制器中被命名为get_pages
,只需写:
class SomeController < ApplicationController
before_filter :get_pages
def get_pages
@pages = Page.all
end
end
Then, on your view, you'll be able to access it as @pages
on all your controller actions. 然后,在您的视图中,您将能够在所有控制器操作上以@pages
访问它。
You could use a helper method like this: 您可以使用这样的辅助方法 :
#app/helpers/application_helper.rb
Class ApplicationHelper
def pages
Page.all
end
end
Helpers are available in your views, so you'll be able to do this: 您可以在视图中找到助手,这样您就可以执行此操作:
#app/views/application/index.html.erb
<% pages.each do |page| %>
<%= page.title %>
<% end %>
Firstly, let me say that your approach is not that wrong imho. 首先,让我说,你的做法是不是错恕我直言。 Introducing an extra method which is just an alias for Page.all
is not really needed, or not really an improvement. 引入一个额外的方法,它只是Page.all
的别名, Page.all
并不需要,或者不是真正的改进。
But there are definitely better approaches. 但肯定有更好的方法。
I would fix this as follows: in ApplicationController
I would add the method 我会修复如下:在ApplicationController
我会添加方法
def get_all_pages
@pages ||= get_all_pages
end
This will make sure that any controller knows that method. 这将确保任何控制器都知道该方法。
Then, if you are sure, you need it on every page, you can just a before_filter
in your ApplicationController
, but generally, I prefer to write it in the controller itself. 然后,如果你确定,你需要在每个页面上,你可以只在ApplicationController
使用before_filter
,但一般来说,我更喜欢在控制器本身中编写它。
Eg 例如
class IdeasController < ApplicationController
before_action :get_all_pages
... the rest of your controller ...
end
Also, I would extract your list of pages into a partial, store in under app/views/shared/_pages_list.html.erb
or app/views/pages/_pages_list.html.erb
and then in your application.html.erb
just call to render the partial instead. 另外,我会将您的页面列表提取到部分,存储在app/views/shared/_pages_list.html.erb
或app/views/pages/_pages_list.html.erb
,然后在您的application.html.erb
调用改为渲染部分。
The method we called sets the instance variable @pages
, it will be available in the view, so your partial would like: 我们调用的方法设置实例变量@pages
,它将在视图中可用,因此您的部分需要:
<ul>
<% @pages.each do |page| %>
<li><%= link_to page.name, page_path(page) %></li>
<% end %>
</ul>
Lastly, for completeness, let me answer how you can make a controller-method available in the view. 最后,为了完整性,让我回答一下如何在视图中使用控制器方法。 In a controller write 在控制器写入
def get_pages
# ..do something
end
helper_method :get_pages
This will make the method get_pages
available in the view, but only for a controller that was responsible for loading/rendering that view. 这将使方法get_pages
在视图中可用,但仅适用于负责加载/呈现该视图的控制器。 So if you want it for all views, define this in ApplicationController
. 因此,如果您想要所有视图,请在ApplicationController
定义它。 Eg this is what we generally do when defining current_user
method. 例如,这是我们在定义current_user
方法时通常所做的。
if you start to get some more code, extract the code related to the page-list-fetching-and-rendering into a separate module, and include that into your ApplicationController
. 如果您开始获得更多代码,请将与页面列表获取和呈现相关的代码提取到单独的模块中,并将其包含在ApplicationController
。 This makes your ApplicationController
more readable. 这使您的ApplicationController
更具可读性。
concerns
were introduced for, so you can use that, if you are on rails 4 注:这正是concerns
被引入,这样你就可以使用,如果你是在轨道上4 a Page
is its own resource, so you could always create a separate PagesController
and make sure it is responsible for rendering the list, and use ajax to fetch on the pages where it is needed. Page
是它自己的资源,所以你总是可以创建一个单独的PagesController
并确保它负责呈现列表,并使用ajax来获取需要它的页面。 This is a really nice solution, but also a bit more work (overkill?). 这是一个非常好的解决方案,但也有一些工作(矫枉过正?)。 But very nicely structured. 但结构非常好。
If so, simply add the following code into action in the controller 如果是这样,只需在控制器中添加以下代码即可
def youraction
@pages = Page.all
end
This will make the global variable @pages available in your view for use. 这将使您的视图中的全局变量@pages可用。 Call it directly as @pages. 直接将其称为@pages。
Another approach would be using an asynchronous call to load the result of PagesController#index
and show it inside your application layout. 另一种方法是使用异步调用来加载PagesController#index
的结果并在应用程序布局中显示它。
$.ajax("<%= pages_path %>").done(function(html) {
$("#pages-list").html(html);
});
To achieve this you could make PagesController#index
render with layout: false
if the request.xhr?
为了实现这一点,你可以使用layout: false
来制作PagesController#index
渲染layout: false
如果request.xhr?
returns true
. 返回true
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.