Substituindo “find” no ActiveRecord da maneira DRY
-
09-06-2019 - |
Pergunta
Eu tenho alguns modelos que precisam ter condições de localização personalizadas colocadas neles.Por exemplo, se eu tiver um modelo Contact, toda vez que Contact.find for chamado, quero restringir os contatos retornados que pertencem apenas à conta em uso.
Encontrei isso no Google (que personalizei um pouco):
def self.find(*args)
with_scope(:find => { :conditions => "account_id = #{$account.id}" }) do
super(*args)
end
end
Isso funciona muito bem, exceto em algumas ocasiões em que account_id é ambíguo, então adaptei-o para:
def self.find(*args)
with_scope(:find => { :conditions => "#{self.to_s.downcase.pluralize}.account_id = #{$account.id}" }) do
super(*args)
end
end
Isso também funciona muito bem, no entanto, quero que esteja SECO.Agora tenho alguns modelos diferentes que desejo que esse tipo de função seja usado.Qual é a melhor maneira de fazer isso?
Ao responder, inclua o código para ajudar nossas mentes a compreender a metaprogramação Ruby-fu.
(Estou usando Rails v2.1)
Solução
Você não nos diz qual versão do Rails você está usando [editar - está no Rails 2.1, portanto, o conselho a seguir está totalmente operacional], mas eu recomendo que você use o seguinte formulário em vez de sobrecarregar o find:
account.contacts.find(...)
isso envolverá automaticamente a descoberta em um escopo onde a cláusula do usuário está incluída (já que você tem o account_id, presumo que você tenha a conta em algum lugar próximo)
Sugiro que você verifique os seguintes recursos sobre escopos
Outras dicas
O conselho de Jean é válido.Supondo que seus modelos sejam assim:
class Contact < ActiveRecord::Base
belongs_to :account
end
class Account < ActiveRecord::Base
has_many :contacts
end
Você deveria estar usando o contacts
associação da conta corrente para garantir que você só receberá Contact
registros com escopo para essa conta, assim:
@account.contacts
Se desejar adicionar mais condições à sua consulta de contatos, você pode especificá-las usando find:
@account.contacts.find(:conditions => { :activated => true })
E se você estiver constantemente consultando usuários ativados, poderá refatorá-lo em um escopo nomeado:
class Contact < ActiveRecord::Base
belongs_to :account
named_scope :activated, :conditions => { :activated => true }
end
Que você usaria assim:
@account.contacts.activated
para dar uma resposta específica ao seu problema, sugiro mover o método mencionado acima para um módulo a ser incluído pelos modelos em questão;então você teria
class Contact
include NarrowFind
...
end
PS.cuidado com o escape sql do account_id, você provavelmente deve usar o :conditions=>[".... =?", $account_id]
sintaxe.