Pergunta

Eu tenho um projeto Rails 3.Com o Rails 3 veio o Arel e a capacidade de reutilizar um escopo para construir outro.Gostaria de saber se existe uma maneira de usar escopos ao definir um relacionamento (por exemplo,um "tem_muitos").

Tenho registros que possuem colunas de permissão.Gostaria de construir um default_scope que leve em consideração minhas colunas de permissão para que os registros (mesmo aqueles acessados ​​através de um relacionamento) sejam filtrados.

Atualmente, no Rails 3, default_scope (incluindo patches que encontrei) não fornece um meio viável de passar um proc (que eu preciso para vinculação tardia de variáveis).É possível definir um has_many para o qual um escopo nomeado pode ser passado?

A ideia de reutilizar um escopo nomeado seria assim:

Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)}
has_many :orders, :scope => Orders.my_orders

Ou codificar implicitamente esse escopo nomeado no relacionamento seria semelhante a:

has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}

Estou simplesmente tentando aplicar default_scope com ligação tardia.Eu preferiria usar uma abordagem Arel (se houver), mas usaria qualquer opção viável.

Como estou me referindo ao usuário atual, não posso confiar em condições que não sejam avaliadas no último momento possível, como:

has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
Foi útil?

Solução

Eu sugiro que você dê uma olhada "Os escopos nomeados estão mortos"

O autor explica aí o quão poderoso o Arel é :)

Espero que ajude.

EDITAR nº 1 de março de 2014

Como afirmam alguns comentários, a diferença agora é uma questão de gosto pessoal.

No entanto, eu ainda recomendo pessoalmente evitar expor o escopo do Arel a uma camada superior (seja um controlador ou qualquer outra coisa que acesse os modelos diretamente), e isso exigiria:

  1. Crie um escopo e exponha-o por meio de um método em seu modelo.Esse método seria aquele que você expõe ao controlador;
  2. Se você nunca expõe seus modelos aos controladores (para ter algum tipo de camada de serviço sobre eles), tudo bem.A camada anticorrupção é seu serviço e ele poderá acessar o escopo do seu modelo sem se preocupar muito com como os escopos são implementados.

Outras dicas

Que tal extensões de associação?

class Item < ActiveRecord::Base
  has_many :orders do
    def for_user(user_id)
      where(user_id: user_id)
    end
  end
end

Item.first.orders.for_user(current_user)

ATUALIZAR:Gostaria de salientar que a vantagem das extensões de associação em oposição aos métodos ou escopos de classe é que você tem acesso aos componentes internos do proxy de associação:

proxy_association.owner retorna o objeto do qual a associação faz parte.proxy_association.reflection retorna o objeto de reflexão que descreve a associação.proxy_association.target retorna o objeto associado para pertence_to ou has_one, ou a coleção de objetos associados para has_many ou has_and_belongs_to_many.

Mais detalhes aqui: http://guides.rubyonrails.org/association_basics.html#association-extensions

Em vez de escopos, acabei de definir métodos de classe, o que tem funcionado muito bem

def self.age0 do
  where("blah")
end

Eu uso algo como:

class Invoice < ActiveRecord::Base
  scope :aged_0,  lambda{ where("created_at IS NULL OR created_at < ?", Date.today + 30.days).joins(:owner) }
end 

Você pode usar mesclar método para mesclar escopos de diferentes modelos.Para mais detalhes procure por merge neste trilhoscast

Se você está apenas tentando receber os pedidos do usuário, por que não usa o relacionamento?

Presumindo que o usuário atual esteja acessível a partir do método current_user em seu controlador:

@my_orders = current_user.orders

Isso garante que apenas os pedidos específicos de um usuário serão mostrados.Você também pode fazer junções aninhadas arbitrariamente para obter recursos mais profundos usando joins

current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top