Vorrei specificare un ordinamento predefinito nel mio modello.
In modo che quando faccio un .where()
senza specificare un .order()
utilizza l'ordinamento predefinito. Ma se specifico un .order()
, sovrascrive quello predefinito.
Vorrei specificare un ordinamento predefinito nel mio modello.
In modo che quando faccio un .where()
senza specificare un .order()
utilizza l'ordinamento predefinito. Ma se specifico un .order()
, sovrascrive quello predefinito.
Risposte:
default_scope
Funziona con Rails 4+:
class Book < ActiveRecord::Base
default_scope { order(created_at: :desc) }
end
Per Rails 2.3, 3, invece, ti serve questo:
default_scope order('created_at DESC')
Per Rails 2.x:
default_scope :order => 'created_at DESC'
Dov'è created_at
il campo in cui si desidera eseguire l'ordinamento predefinito.
Nota: ASC è il codice da utilizzare per Ascendente e DESC per Discendente ( desc
, NOT dsc
!).
scope
Una volta abituato, puoi anche usare scope
:
class Book < ActiveRecord::Base
scope :confirmed, :conditions => { :confirmed => true }
scope :published, :conditions => { :published => true }
end
Per Rails 2 è necessario named_scope
.
:published
scope ti dà Book.published
invece di
Book.find(:published => true)
.
Da Rails 3 puoi "concatenare" questi metodi concatenandoli con punti tra loro, quindi con gli ambiti sopra puoi ora usare Book.published.confirmed
.
Con questo metodo, la query non viene effettivamente eseguita fino a quando non sono necessari risultati effettivi (valutazione lazy), quindi è possibile concatenare 7 ambiti insieme ma solo 1 query del database effettiva, per evitare problemi di prestazioni dall'esecuzione di 7 query separate.
È possibile utilizzare un parametro passato come una data o un user_id (qualcosa che cambierà in fase di esecuzione e quindi avrà bisogno di una "valutazione pigra", con un lambda, come questo:
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 puoi disabilitare l'ambito predefinito con:
Book.with_exclusive_scope { find(:all) }
o anche meglio:
Book.unscoped.all
che disabiliterà qualsiasi filtro (condizioni) o ordinamento (ordina per).
Nota che la prima versione funziona in Rails2 + mentre la seconda (senza frame) è solo per Rails3 +
Quindi
... se stai pensando, hmm, quindi questi sono proprio come metodi allora ... sì, è esattamente quello che sono questi scopi!
Sono come avere, def self.method_name ...code... end
ma come sempre con il rubino sono delle belle scorciatoie sintattiche (o "zucchero") per rendere le cose più facili per te!
In realtà sono metodi a livello di classe in quanto operano su 1 set di record "tutti".
Il loro formato sta tuttavia cambiando, con le rotaie 4 ci sono avvisi di deprecazione quando si utilizza #scope senza passare un oggetto richiamabile. Ad esempio scope: red, dove (color: 'red') dovrebbe essere cambiato in scope :red, -> { where(color: 'red') }
.
Come nota a margine , se usato in modo errato, _scope predefinito può essere utilizzato in modo improprio / abusato.
Si tratta principalmente di quando viene utilizzato per azioni come where
limitare (filtrare) la selezione predefinita (una cattiva idea per un valore predefinito) piuttosto che essere utilizzato solo per ordinare i risultati.
Per le where
selezioni, basta usare i normali ambiti con nome. e aggiungere tale ambito nella query, ad es. Book.all.published
dove si published
trova un ambito denominato.
In conclusione, gli ambiti sono davvero fantastici e ti aiutano a spingere le cose verso l'alto nel modello per un approccio DRYer "modello grasso modello sottile".
default_scope { order("#{table_name}.created_at DESC") }
?
default_scope { order(created_at: :desc) }
4.2.6
sembra updated_at
non ordinare created_at
.
updated_at
per impostazione predefinita? : - |
Un rapido aggiornamento all'eccellente risposta di Michael sopra.
Per Rails 4.0+ devi mettere il tuo ordinamento in un blocco come questo:
class Book < ActiveRecord::Base
default_scope { order('created_at DESC') }
end
Si noti che l'istruzione dell'ordine viene posizionata in un blocco indicato dalle parentesi graffe.
L'hanno cambiato perché era troppo facile passare in qualcosa di dinamico (come l'ora corrente). Questo rimuove il problema perché il blocco viene valutato in fase di esecuzione. Se non usi un blocco otterrai questo errore:
Il supporto per la chiamata di #default_scope senza blocco viene rimosso. Ad esempio invece di
default_scope where(color: 'red')
, si prega di utilizzaredefault_scope { where(color: 'red') }
. (In alternativa puoi semplicemente ridefinire self.default_scope.)
Come menziona @Dan nel suo commento qui sotto, puoi fare una sintassi più ruby come questa:
class Book < ActiveRecord::Base
default_scope { order(created_at: :desc) }
end
o con più colonne:
class Book < ActiveRecord::Base
default_scope { order({begin_date: :desc}, :name) }
end
Grazie @ Dan !
default_scope { order(created_at: :desc) }
se, come me, si tenta di ridurre al minimo la sintassi sql in rails. <br/> Se si hanno più colonne da ordinare e si desidera utilizzare la nuova sintassi, potrebbe essere necessario racchiudere la descrizione colonne in baffi come questodefault_scope { order({begin_date: :desc}, :name) }
È possibile utilizzare default_scope per implementare un ordinamento predefinito http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html
default_scope
su quella pagina, perché è stato refactored da ActiveRecord::Base
in ActiveRecord::Scoping::Default::ClassMethods
( api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/… )