Misturando ActiveRecord encontrar as condições
-
01-07-2019 - |
Pergunta
Eu quero encontrar registros em uma combinação de created_on,> = alguma data e nome em alguma lista de nomes.
Para "> =" Eu teria que usar condição sql. Para "IN" Eu teria que usar um hash de condições em que a chave é:. Nome e o valor é o conjunto de nomes
Existe uma maneira de combinar os dois?
Solução
Você pode usar escopos no Rails 2.1 e acima chamado
Class Test < ActiveRecord::Base
named_scope :created_after_2005, :conditions => "created_on > 2005-01-01"
named_scope :named_fred, :conditions => { :name => "fred"}
end
então você pode fazer
Test.created_after_2005.named_fred
ou você pode dar named_scope um lambda que lhe permite passar argumentos
Class Test < ActiveRecord::Base
named_scope :created_after, lambda { |date| {:conditions => ["created_on > ?", date]} }
named_scope :named, lambda { |name| {:conditions => {:name => name}} }
end
então você pode fazer
Test.created_after(Time.now-1.year).named("fred")
Outras dicas
Se você estiver usando uma velha Rails versão, consulta de Honza está perto, mas você precisa adicionar parênteses para as cordas que são colocados no estado em:
Person.find(:all, :conditions => ["created_at > ? AND name IN (?)", date, names])
Usando IN pode ser um saco misturado: é mais rápido para inteiros e mais lento para uma lista de strings. Se você está usando apenas um nome, definitivamente usar um igual operador:
Person.find(:all, :conditions => ["created_at > ? AND name = ?", date, name])
A coisa legal sobre named_scopes é que eles trabalham em coleções demasiado:
class Post < ActiveRecord::Base
named_scope :published, :conditions => {:status => 'published'}
end
@post = Post.published
@posts = current_user.posts.published
Para saber mais sobre named_scopes ver anúncio de Ryan eo Railscast em named_scopes
class Person < ActiveRecord::Base
named_scope :registered, lambda { |time_ago| { :conditions => ['created_at > ?', time_ago] } }
named_scope :with_names, lambda { |names| { :conditions => { :names => names } } }
end
Se você estiver indo para passar variáveis ??para os escopos que você tem que usar um lambda.
Você pode encadear a cláusula where
:
Person.where(name: ['foo', 'bar', 'baz']).where('id >= ?', 42).first
Os escopos nomeados já propostos são muito bem. A maneira clássica de fazer isso seria:
names = ["dave", "jerry", "mike"]
date = DateTime.now
Person.find(:all, :conidtions => ["created_at > ? AND name IN ?", date, names])
Eu acho que tanto vou usar localizadores AR simples ou Searchgasm .