4

我一直在尝试找到一种干净的方法来确定一个动作(在 Rails 控制器中)是否适用于成员或集合。

例如,当您在 routes.rb 中声明时

resources :projects

您将获得以下“在集合上”定义的方法:

  • 指数
  • 创造
  • 新的

并且在“成员”上定义了以下内容:

  • 更新
  • 节目
  • 删除

我正在尝试找到一种方法来在视图中利用这种出色的模式,例如:

<% if @controller.action.applies_on_members? %>
  <%= link_to :destroy, :method => "delete", :confirm => "RU Sure" %>
  <%= link_to :show, "show" %>
<% end %>

同样,这在 before_filters 中可能很有用

before_filter :find_project, :only_on_members => true

目前我必须执行以下操作:

before_filter :find_project, :except => [:new, :create, :index, :export_all, :destroy_all, :archive_all]

这很烦人,我的想法是所有这些动作都有一个共同的行为:它们是在collections上定义的。

有谁知道如何以干净的方式实现这一目标?

注意:我问这个问题的原因是因为我正在寻找一些可扩展的开发方面,例如 before_filters 或某些部分的行为会自动被新的自定义操作继承。

谁从来不需要写下类似的东西

<% unless ["new", "index", "some_other_action1", "some_other_action2", "some_other_action3", "some_other_action4"].include? @controller.action_name %>
  <%= link_to "Destroy", :project, :method => :delete %>  
<% end %>
4

3 回答 3

2

在发布这个问题将近一年后,我知道已经为这个问题找到了一个合理的解决方案。

如果我们看看实际做了什么on => :memberon => :collection区别基本上是 on => :member生成了一个包含:id参数的路径,而on => :collection版本没有。

然后,一个简单的解决方案将params[:id]在自定义方法中测试是否为空白。它看起来像这样(比如在 中application_controller.rb):

class ApplicationController < ActionController::Base

  def on_member?
    !params[:id].blank?
  end

  helper_method :on_member? #method will be accessible in views
end

例如,如本文所述,我们可以在 before_filter 中执行以下操作:

before_filter :find_project, :if => :on_member?

在视图中,这使我可以检查这样的方法:

<% if on_member? %>
  <%= link_to :destroy, :method => "delete", :confirm => "RU Sure" %>
  <%= link_to :show, "show" %>
<% end %>
于 2014-03-03T17:22:20.633 回答
1

首先,对集合及其条目进行操作的模式是REST的一部分,它是 Rails 的支柱之一。您所确定的本质上就是 REST 所称的collectionsentries。理论上,您可以在集合或该集合中的条目上应用最常见的 HTTB 动词,其中: GET ; 检索,PUT;替换,发布;创建和删除;破坏。虽然有点不清楚 POST 会在单个条目上做什么。

然而,在实践中,在 Rails 中,您通常使用您已经确定的那些:

  • 收藏品
    • 创建条目 ( POST )
    • 查看条目 ( GET )
  • 入口
    • 更新条目 ( PUT )
    • 显示条目 ( GET )
    • 删除条目 ( DELETE )

这些是 Rails 添加的 RESTful 路由。然而,正如您所知,Rails 还包含另外两个操作来实现一个用户页面,该页面可以为这些端点提供必要的数据。(编辑),

我很少看到人们得出这些定义。在我看来,如果你真的想解决这个问题,至少有两种方法可以解决这个问题(见帖子底部):

您可以使用猴子补丁“_normalize_callback_options”来获得您建议的确切语法。这是相对简单的,但如果上游改变了任何结构,你必须改变你的补丁,因此它不是很可持续。因此,我不推荐这种方法,无论合成糖看起来多么有品位。当然你也可以尝试在上游提交,但由于下面提到的原因,它不太可能被接受。:-)

相反,我会将您的定义放在初始化程序中:config/initializer/rest.rb

ENTRY_ACTIONS      = [:edit, :new, :show, :delete, :update]
COLLECTION_ACTIONS = [:create, :index]

然后在您的过滤器中使用它们,例如:

before_filter :find_project, only: ENTRY_ACTIONS

要在您的视图中访问,请向您的应用程序助手添加一个entry_action?and方法:collection_action?

module ApplicationHelper
  def entry_action?
    ENTRY_ACTIONS.include?(controller.action_name.to_sym)
  end

  def collection_action?
    COLLECTION_ACTIONS.include?(controller.action_name.to_sym)
  end
end

那么在你看来:

<% if entry_action? %>
   # code
<% end %>

我自己不会将其提取为常量,而只是直接编写数组,因为我认为稍后回来阅读时会更清楚。此外,大多数人每次遇到这些远非最佳的方法时都必须三思而后行。

于 2013-05-27T14:16:33.203 回答
0

您正在处理一个非常常见的问题,该问题已经在 Rails 中为我们解决了,并且几乎将其颠倒过来。与其向控制器询问其在整个应用程序中的状态,不如告诉视图和控制器去做它需要做的事情,但它知道如何去做。

由于您已经确定index,createnew操作适用于“集合”,而update,showdelete适用于“成员”,您应该定义每个相应的控制器操作和视图以使用这些形式的资源。

回到您给出的示例,链接应该在部分中定义,并让适当的视图模板呈现部分。

你的before_filter应该写成before_filter :find_project, :only => [:update, :show, :delete].

只要想到在您的应用程序中看到对所有地方的调用,就会@controller.action.applies_on_members?在我心中升起一个标志,即您需要重新考虑您的设计。同样,您正在尝试解决 Rails 已经为您解决的问题。

于 2013-05-27T14:22:33.297 回答