在使用条件 before_action/before_filter 时,是否需要使用 "proc"?

44

看哪,一个before_filter

class ThingController < ApplicationController
  before_filter :check_stuff, :if => proc {Rails.env.production?}
end

在最近的代码审查中,有人问我:"这是否需要proc才能正常工作?" 答案似乎是'是',但这是一个合理的问题,我本来想通过参考Rails文档或指南或关于使用条件语句与before_filter(现在是before_action的别名)的内容来回答它。

我找不到任何相关信息。 Action Controller指南提到了:only/:except,但没有提到:if/:unless

如果找不到,那么代码中是否有我可以指向的位置涵盖此内容?它在这里简要提到,但更多地关于如何处理:only:except,而不是:if:unless

5个回答

63

在Rails指南上找到了它:http://guides.rubyonrails.org/active_record_callbacks.html#conditional-callbacks

结果证明,不一定需要一个Proc才能使它起作用。

:if:unless选项可以使用符号、字符串、ProcArray

所以在你的情况下,你可能只需要

before_action :check_stuff, if: "Rails.env.production?"

有时在Rails文档中查找东西很麻烦,但至少像这样的问题会随着时间的推移使事情变得更容易找到,因为StackOverflow被很好地索引并具有高搜索排名。


2
从技术上讲,这些是 ActiveRecord 回调,而不是 ActionController 回调,但我想选项语法是相同的。我不确定我是否喜欢 eval 字符串比 Proc 更好,但感谢您找到了文档。 - MrTheWalrus
4
看起来ActionController和ActiveRecord使用相同的 ActiveSupport::Callbacks 实现:http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.htmlActionController对:only:except选项进行了一些规范化处理,以将它们转换为ActiveSupport::Callbacks所期望的:if:unless选项。 - adamesque

29

从Rails 5.2开始,当前接受的答案将不再有效,并且将字符串传递给条件语句将会失败。

警告:将字符串传递给:if和:unless条件选项已被弃用,并将在Rails 5.2中被删除,没有替代方案。

未来,使用proc现在是添加条件的最佳方式,就像原始问题中所示:

class ThingController < ApplicationController
  before_action :check_stuff, :if => proc {Rails.env.production?}
end

12

我以前在我的代码中做过这个。希望这个例子能对你有所帮助。如果你能使用if语句,但是应该像我这里所做的那样指向另一个方法。

class Admin::ArticlesController < ApplicationController
  before_filter :deny_access, :unless => :draft_and_admin?

  def show
    @article = Article.find(params[:id])
  end

  protected

  def draft_and_admin?
    Article.find(params[:id]).draft? && current_user.admin?
  end
end

1
这很有用,但并没有解决我的实际问题,我的问题是关于文档的。 - MrTheWalrus
不会有关于 if 和 unless 的文档,因为人们在方法内部使用条件。 - jimagic
这太棒了。 - Scott Hillson

8

我建议使用箭头函数(stabby lambda)。如果你想知道为什么,请参考此链接

class ThingController < ApplicationController
  before_action :check_stuff, if: -> { Rails.env.production? }
end

这句话的意思是“这个答案几乎等同于Upvote Me的回答”。

0
添加一个方法来检查 before_actionif/unless 条件应该是最佳方式,因为这样您可以轻松适应未来任何额外的更改。
class ThingController < ApplicationController
  before_filter :check_stuff, if: :check_stuff?

  def check_stuff
  end

  private

  def check_stuff?
    Rails.env.production?
  end
end

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