包含OR的复杂SQL语句的Rails作用域



我现在正在做一个小型Rails项目。我正在使用Pundit来授权控制器的操作和其他东西。现在的工作是使用Pundit进行索引操作,并使用我的控制器中的Pundit的policy_scope来获取用户可以看到的项目。

用户应该能够通过以下三种方式查看项目:-他是主人-他被邀请了-该项目为公共

我现在已经尝试了几种解决方案,但最终完成了以下操作:

scope :public_or_involved, -> (user) { 
  joins('LEFT JOIN invitations ON invitations.project_id = projects.id').
  where('projects.is_public = TRUE OR projects.owner_id = ? OR invitations.reciever_id = ?', user.id, user.id) 
}

这是我在project_policy.rb:中使用以下专家范围的唯一方法

class Scope
  attr_reader :user, :scope
  def initialize(user, scope)
    @user = user
    @scope = scope
  end
  def resolve
    scope.public_or_involved(user)
  end
end

最后,我的问题是:

有没有一种优雅的方式来做我现在正在做的事情感觉很难看,不像铁轨!

注意,我不认识专家(我更喜欢acl9的简单DSL方法),所以我只是真正为您转换查询,您通常可以让Rails给您一个LEFT JOINincludes(),您可以使用这个小技巧来获得更整洁的OR:

scope :public_or_involved,
  -> (user) { includes(:invitations).where(
    where( is_public: true, owner_id: user.id, invitations: { receiver_id: user.id } ).where_values.reduce(&:or)
  )}

根据我的经验,您现在拥有的解决方案是最好的。您可以使用Arel、Squeel或MetaWhere之类的东西来Ruby fy SQL字符串,但这些都会增加复杂性。

如果这符合您的要求,我不会太担心让它"更像Rails-y"

最新更新