在Scope中添加条件返回(能够根据条件链接范围中的范围)

时间:2014-05-30 23:14:33

标签: ruby-on-rails-3

我有一个带有条件的经常性代码,最近添加了新的权限代码。它不是从一开始就设计的,所以它有点混乱:

@usuarios = Usuario.menores_de_edad.con_autorizacion(params[:autorizacion]).con_nombre(params[:nombre])
# master puede ver todos, así que ignora los permisos
if !usuario_actual.es_master?
  if usuario_actual.permiso.blank?
    # Si es admin y no tiene permisos establecidos
    @usuarios = Usuario.where(id: nil)
  else
    # Lee de que niveles puedes mostrar los usuarios
    @usuarios = @usuarios.del_nivel(usuario_actual.permiso.niveles)
  end
end
if usuario_actual.es_admin_occ?
  @usuarios = @usuarios.de_occ
end

我想以这种方式将其作为范围:

@usuarios = Usuario.menores_de_edad.con_autorizacion(params[:autorizacion]).con_nombre(params[:nombre])
@usuarios = @usuarios.permitibles(usuario_actual)

我怎样才能让它发挥作用?我现在有这个:

class Usuario < ActiveRecord::Base
  scope :permitibles, lambda{ |usuario_actual|
    # master can see everything, so, don't scope anything at all
    if !usuario_actual.es_master?
      if usuario_actual.permiso.blank?
        # return nothing if you don't have permissions
        where(id: nil)
      else
        # this is a scope
        del_nivel(usuario_actual.permiso.niveles)
      end

      if usuario_actual.es_admin_occ?
        # this is a scope
        de_occ
      end
    end
  }
end

问题是,在范围内,我不知道如何连接其他范围,我的意思是,&#34; de_occ&#34;必须根据其他条件进行链接,但是现在这将不会按原样运行,因为它只返回一个范围而不是链接&#34; de_occ&#34;到第一个条件。我怎样才能做到这一点?

谢谢!

1 个答案:

答案 0 :(得分:1)

好的,通过你的代码对我来说没什么问题。最佳做法是不要使用母语langauge作为模型和方法名称的来源。

您的问题的基本方法是将逻辑移动到方法中并链接范围/ sqls。这是一个概念证明:

scope :menores_de_edad, ->() {where(something: true)}
scope :del_nivel, ->(params) {where(field: param)}
scope :de_occ, ->() { ... }


def self.we_are_chaining_scopes
   result = self.scoped

   if !usuario_actual.es_master?
      if usuario_actual.permiso.blank?
        # return nothing if you don't have permissions
        result = result.menores_de_edad 
      else
        # this is a scope
         result = result.del_nivel(usuario_actual.permiso.niveles)
      end

      if usuario_actual.es_admin_occ?
        # this is a scope
        result = result.de_occ
      end

    end

   result
end 

您可以通过为此查询创建服务对象来使其更加出色。粗略的例子:

class SpecificQuery
  def initialize(relation = Model.scoped)
    @relation = relation
  end

 private

  def scoped_to(&block)
    @relation = @relation.instance_eval(&block)
  end

 def scoped_behavior_method_one(param)
    scoped_to { where(:something: param) }
  end

 def scoped_behavior_method_two(param)
    scoped_to { ... }
  end
end

然后你可以很好地链接范围+你将封装不一定属于你的模型的逻辑。此外,编写规范更容易:)我希望有所帮助。