Ruby on rails 确定操作是针对成员还是针对集合

Ruby on rails 确定操作是针对成员还是针对集合,ruby-on-rails,ruby,controller,Ruby On Rails,Ruby,Controller,我一直在试图找到一种干净的方法来确定某个操作(在rails控制器中)是应用于成员还是应用于集合 例如,当您在routes.rb中声明 resources :projects 您可以在“集合”上定义以下方法: 索引 创造 新的 以下是关于“成员”的定义: 更新 展示 删除 我正试图找到一种在视图中利用这种伟大模式的方法,例如: <% if @controller.action.applies_on_members? %> <%= link_to :destroy,

我一直在试图找到一种干净的方法来确定某个操作(在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_filter :find_project, :except => [:new, :create, :index, :export_all, :destroy_all, :archive_all]
这很烦人,我的想法是所有这些操作都有一个共同的行为:它们是在集合上定义的

有人知道如何以干净的方式实现这一点吗

NB:我问这个问题的原因是因为我正在寻找一些在开发方面可伸缩的东西,比如before_过滤器或某些部分的行为会自动被新的自定义操作继承。

从来没有写过这样的东西

<% 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 %>

:删除%>

首先,对集合及其条目进行操作的模式是Rails的支柱之一。您所识别的基本上是REST所称的集合条目。理论上,您可以对集合或集合中的条目进行应用,其中:GET;检索,放置;替换,POST;创建并删除;摧毁。虽然有点不清楚POST在一个条目上会做什么

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

  • 收藏
    • 创建条目(POST
    • 查看条目(GET
  • 入口
    • 更新条目(PUT
    • 显示条目(GET
    • 删除条目(删除
这些是Rails添加的RESTful路由。但是,正如您所知,Rails还将另外两个操作装箱,以实现一个用户页面,该页面可以向这些端点提供必要的数据。(新建编辑

我很少看到有人会下这样的定义。在我看来,如果你真的想解决这个问题,至少有两种方法可以解决这个问题(见文章底部):

您可以使用monkey patch来获得您建议的确切语法。这是相对直接的,但如果上游改变了结构的任何东西,你必须改变你的补丁,因此它不是很可持续。因此,我不推荐这种方法,不管合成糖看起来有多美味。当然,您也可以尝试向上游提交,但由于以下原因,它不太可能被接受。:-)

相反,我将把您的定义放在一个初始值设定项中:
config/initializer/rest.rb

ENTRY_ACTIONS      = [:edit, :new, :show, :delete, :update]
COLLECTION_ACTIONS = [:create, :index]
然后在过滤器中使用它们,如:

before_filter :find_project, only: ENTRY_ACTIONS
要在视图中进行访问,请向应用程序助手添加一个
entry\u action?
collection\u 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 %>

#代码

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

您正在为我们解决一个在Rails中已经解决的非常常见的问题,并且几乎将其颠倒过来。您不应该在应用程序中询问控制器的状态,而应该让视图和控制器执行它需要执行的操作,尽管它知道如何执行

由于您已经确定
索引
创建
新建
操作适用于“集合”,并且
更新
显示
删除
操作适用于“成员”,因此您应该定义每个相应的控制器操作和视图以使用这些形式的资源

回到您给出的示例,应该在局部中定义链接,并使用适当的视图模板渲染局部

您的
before\u filter
应该写为
before\u filter:find\u project,:only=>[:update,:show,:delete]


一想到应用程序中到处都能看到对
@controller.action.applications\u成员的调用?
,我就觉得你需要重新考虑你的设计。同样,您正在尝试解决Rails已经为您解决的问题。

发布此问题将近一年后,我知道您已经找到了解决此问题的合理方法

如果我们看一下
on=>:member
on=>:collection
真正做了什么,基本上区别在于
on=>:member
生成了一个包含
:id
参数的路径,而
on=>:collection
版本没有

然后,一个简单的解决方案是测试自定义方法中的
params[:id]
是否为空。它看起来是这样的(比如在
应用程序\u controller.rb
):

在视图中,这允许我检查以下方法:

<% if on_member? %>
  <%= link_to :destroy, :method => "delete", :confirm => "RU Sure" %>
  <%= link_to :show, "show" %>
<% end %>

“删除”,:确认=>“确定”%>

[问题更新]感谢您的回答。事实上,我一直在寻找一个可扩展的解决方案,这样当我添加一个新动作时,我的视图和控制器就不必在显示给用户的beforu过滤器和动作方面做太多的更改。常量解决方案不正适合这样做吗?虽然我还是会说,如果你的控制器有这么多的动作,你想做的话,这是一种代码味道。在这种情况下,在过滤之前将不同控制器中的相同数组传递给
,这不会违反DRY,而是创建可读代码。这将解决(简单的)问题。
class ApplicationController < ActionController::Base

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

  helper_method :on_member? #method will be accessible in views
end
before_filter :find_project, :if => :on_member?
<% if on_member? %>
  <%= link_to :destroy, :method => "delete", :confirm => "RU Sure" %>
  <%= link_to :show, "show" %>
<% end %>