Rails 和 before_action 具有不同的条件

Rails and before_action with different conditionals

我在控制器中设置了这些 before_action

before_action :require_user, unless: :public?, only: [:show]
before_action :require_user, only: [:index, :edit, :update]

基本上,只有当 public? 为 false 时,我才会尝试在 show 操作中执行过滤器 required_front_user

对于其余的操作,我希望始终执行过滤器。

看起来第一个 before_action 设置被第二个设置忽略并完全覆盖。

是否可以使用 before_action 语句将两种组合结合起来,还是我必须在过滤器中自行实现此逻辑?

更新

这也行不通:

before_action :require_user, if: :public?, only: [:index, :edit, :update]
before_action :require_user, unless: :public?, only: [:show, :index, :edit, :update]

我以为如果public? returns true 会加载第一个设置,如果false 会加载第二个设置。碰巧只有第二个设置被加载,如果 public? == true 永远不会触发 before_action

更新 2

这是我发现它有效的方法:

before_action :require_user_when_public, if: :public?, only: [:index, :edit, :update]
before_action :require_user_when_no_public, unless: :public?, only: [:show, :index, :edit, :update]

protected

def require_user_when_public
  require_user
end

def require_user_when_no_public
  require_user
end

非常难看:/

before_action :require_user, only: require_user_before_actions

private

def require_user_before_actions
 actions = [:index, :edit, :update]
 actions << :show unless public?
 actions
end

我只测试了一点点所以不太确定它会起作用,但可能是这样的:

before_action :require_user, if: ->(c) {
  [:index, :edit, :update, !public? && :show].include?(c.action_name.to_sym)
}

作为一个可能愚蠢/损坏的(据我所知,这似乎对我来说在基本测试中有效)替代方案,可能是这样的:

class <<self
  alias_method :old_before_action, :before_action
end

def self.before_action(*callbacks)
  options = callbacks.extract_options!
  if options[:only] && options[:only].is_a?(Proc)
    only_proc = options.delete(:only)
    if_proc = ->(c) { Array(only_proc.(c)).reject(&:blank?).map(&:to_s).to_set.include? c.action_name }
    options[:if] = Array(options[:if]).unshift(if_proc)
  end
  old_before_action(*callbacks, options)
end

before_action :require_user, only: ->(c) { [:index, :edit, :update, !public? && :show] }

我找到的最干净的方法是:

before_action :require_user, only: [:index, :edit, :update]
before_action :require_user_when_no_public, unless: :public?, only: [:show]

protected 

def require_user_when_no_public
  require_user
end