Gostaria de especificar uma ordem de classificação padrão no meu modelo.
Assim, quando eu faço um .where()
sem especificar um, .order()
ele usa a classificação padrão. Mas se eu especificar um .order()
, ele substituirá o padrão.
Gostaria de especificar uma ordem de classificação padrão no meu modelo.
Assim, quando eu faço um .where()
sem especificar um, .order()
ele usa a classificação padrão. Mas se eu especificar um .order()
, ele substituirá o padrão.
Respostas:
default_scope
Isso funciona para o Rails 4+:
class Book < ActiveRecord::Base
default_scope { order(created_at: :desc) }
end
Para o Rails 2.3, 3, você precisa disso:
default_scope order('created_at DESC')
Para o Rails 2.x:
default_scope :order => 'created_at DESC'
Onde created_at
é o campo no qual você deseja que a classificação padrão seja feita.
Nota: ASC é o código a ser usado para Crescente e DESC é para decrescente ( desc
, NÃO dsc
!).
scope
Depois de se acostumar, você também pode usar scope
:
class Book < ActiveRecord::Base
scope :confirmed, :conditions => { :confirmed => true }
scope :published, :conditions => { :published => true }
end
Para o Rails 2, você precisa named_scope
.
:published
escopo fornece a você em Book.published
vez de
Book.find(:published => true)
.
Desde o Rails 3, você pode 'encadear' esses métodos, concatenando-os com períodos entre eles; portanto, com os escopos acima, agora você pode usar Book.published.confirmed
.
Com esse método, a consulta não é realmente executada até que os resultados reais sejam necessários (avaliação lenta); portanto, 7 escopos podem ser encadeados, mas resultando apenas em 1 consulta real no banco de dados, para evitar problemas de desempenho ao executar 7 consultas separadas.
Você pode usar um parâmetro passado como uma data ou um user_id (algo que será alterado no tempo de execução e, portanto, precisará dessa 'avaliação lenta', com um lambda, assim:
scope :recent_books, lambda
{ |since_when| where("created_at >= ?", since_when) }
# Note the `where` is making use of AREL syntax added in Rails 3.
Finalmente, você pode desativar o escopo padrão com:
Book.with_exclusive_scope { find(:all) }
ou melhor ainda:
Book.unscoped.all
que desativará qualquer filtro (condições) ou classificação (ordenar por).
Observe que a primeira versão funciona no Rails2 +, enquanto a segunda (sem escopo) é apenas para o Rails3 +
Então
... se você está pensando, hmm, então esses são apenas métodos, então ... sim, é exatamente isso que esses escopos são!
Eles são como ter, def self.method_name ...code... end
mas como sempre com ruby, são pequenos atalhos sintáticos (ou "açúcar") para facilitar as coisas para você!
Na verdade, eles são métodos de nível de classe, pois operam no conjunto 1 de 'todos' registros.
Seu formato está mudando, no entanto, com os trilhos 4, há aviso de reprovação ao usar #scope sem passar um objeto que pode ser chamado. Por exemplo, scope: red, onde (color: 'red') deve ser alterado para scope :red, -> { where(color: 'red') }
.
Como observação, quando usado incorretamente, o _scope padrão pode ser mal utilizado / abusado.
Isso ocorre principalmente quando é usado para ações como where
limitar (filtrar) a seleção padrão (uma má idéia para um padrão), em vez de apenas ser usado para ordenar resultados.
Para where
seleções, basta usar os escopos nomeados regulares. e adicione esse escopo na consulta, por exemplo, Book.all.published
onde published
está um escopo nomeado.
Em conclusão, os escopos são realmente ótimos e ajudam você a inserir as coisas no modelo para uma abordagem DRYer de 'modelo fino de controlador de gordura'.
default_scope { order("#{table_name}.created_at DESC") }
?
default_scope { order(created_at: :desc) }
4.2.6
parece classificar por updated_at
não created_at
.
updated_at
por padrão? : - |
Uma atualização rápida da excelente resposta de Michael acima.
Para o Rails 4.0+, você precisa colocar sua classificação em um bloco como este:
class Book < ActiveRecord::Base
default_scope { order('created_at DESC') }
end
Observe que a declaração de ordem é colocada em um bloco indicado pelas chaves.
Eles mudaram porque era muito fácil transmitir algo dinâmico (como a hora atual). Isso remove o problema porque o bloco é avaliado em tempo de execução. Se você não usar um bloco, receberá este erro:
O suporte para chamar #default_scope sem um bloco foi removido. Por exemplo, em vez de
default_scope where(color: 'red')
, por favor usedefault_scope { where(color: 'red') }
. (Como alternativa, você pode apenas redefinir self.default_scope.)
Como @Dan menciona em seu comentário abaixo, você pode fazer uma sintaxe mais rubyish como esta:
class Book < ActiveRecord::Base
default_scope { order(created_at: :desc) }
end
ou com várias colunas:
class Book < ActiveRecord::Base
default_scope { order({begin_date: :desc}, :name) }
end
Obrigado @Dan !
default_scope { order(created_at: :desc) }
se você tentasse minimizar a sintaxe sql nos rails. <br/> Se você tem várias colunas para ordenar e deseja usar a nova sintaxe, pode ser necessário agrupar a descrição desc. colunas em bigodes como estedefault_scope { order({begin_date: :desc}, :name) }
Você pode usar o default_scope para implementar uma ordem de classificação padrão http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html
default_scope
nessa página, porque foi reformulado a partir de ActiveRecord::Base
dentro ActiveRecord::Scoping::Default::ClassMethods
( api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/... )