Cos'è scope / named_scope in rails?


105

Recentemente ho iniziato uno stage. Il mio datore di lavoro usa ruby ​​on rails e spesso incontro una nuova sintassi che devo cercare per capire. Ho cercato su Google una buona spiegazione di named_scope, ma quello che ho trovato finora sono principalmente post di blog che ne danno grandi elogi, piuttosto una definizione o un'introduzione diretta.

Cos'è esattamente named_scope (ora chiamato semplicemente scope) in ruby ​​on rails?



2
Questo post del blog è stato prezioso per me quando ho imparato a conoscere gli ambiti denominati: ryandaigle.com/articles/2008/8/20/…
Peter Brown

@notapatch il link è morto ne hai un altro?
mbigras

Ryan Daigle: Named Scope: non è solo per condizioni, sai ?: web.archive.org/web/20160306110506/http://…
notapatch

Risposte:


212

Un ambito è un sottoinsieme di una raccolta. Sembra complicato? Non lo è. Immagina questo:

Hai utenti. Ora, alcuni di questi utenti sono iscritti alla tua newsletter. Hai contrassegnato coloro che ricevono una newsletter aggiungendo un campo al database degli utenti (user.subscripts_to_newsletter = true). Naturalmente, a volte vuoi ottenere quegli utenti che sono iscritti alla tua newsletter.

Ovviamente potresti sempre farlo:

User.where(subscribed_to_newsletter: true).each do #something

Invece di scrivere sempre questo, potresti, tuttavia, fare qualcosa del genere.

#File: users.rb
class User < ActiveRecord::Base
  scope :newsletter, where(subscribed_to_newsletter: true)
  #yada yada
end

Se stai usando Rails 4 o più recente , fallo invece:

#File: users.rb
class User < ActiveRecord::Base
  scope :newsletter, -> { where(subscribed_to_newsletter: true) }
  #yada yada
end

Ciò ti consente di accedere ai tuoi abbonati semplicemente facendo questo:

User.newsletter.each do #something

Questo è un esempio molto semplice, ma in generale gli ambiti possono essere strumenti molto potenti per facilitare il tuo lavoro.

Dai un'occhiata a questo link: Descrizione API


7
Posso chiedere quali sono i vantaggi di questo rispetto, ad esempio, definire un metodo nella classe utente chiamato 'sottoscrittoUsers'? es. 'def self.subscriptsUsers self.where (: subscriptions_to_newsletter => true) end
redroot

3
@redroot il vantaggio è che la scopesintassi è molto più pulita, si ottiene lo stesso risultato ma con una sola riga
Aldo 'xoen' Giambelluca

9
@redroot C'era un grande vantaggio in termini di efficienza, poiché gli ambiti interrogavano pigramente il database mentre i metodi lo facevano avidamente. In Rails 3, anche i metodi sono diventati pigri, quindi ora la differenza è più sintattica. Fonte
evanrmurphy

Il link alla documentazione dell'API è interrotto, aggiorna api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/…
Lohith MV

Consente inoltre di utilizzare il collegamento di
Benjineer

34

L'ambito nel record attivo è come i metodi di classe ma restituiscono l'oggetto Relation, il che significa che è possibile chiamare un altro ambito o un metodo di query del record attivo su di esso.

Ad esempio, se hai un modello Zombie (tabella degli zombi) con metodi di ambito menzionati di seguito,

class Zombie
  scope :rotting, -> { where(rotting: true) }
  scope :fresh, -> { where('age < ?', 25) }
  scope :recent, -> { order(created_at: :desc) }
end

E tu chiami

Zombie.rotting.fresh.recent.limit(3)

Si traduce in quanto segue in SQL,

select "zombies.*" from "zombies" where "zombies"."rotting" = 't' and (age<20) order by create_at desc limit 3

L'esempio sopra è basato sulla sintassi di rails 4


Non riesco a trovare un esempio di ordine (: created_at,: desc) in nessuna documentazione. È possibile che intendevi scope :recent, -> { order(created_at: :desc) }? apidock.com/rails/v4.2.9/ActiveRecord/QueryMethods/order
notapatch

7

Il modo migliore per comprendere i dettagli è andare alla documentazione API.

Otterrai i dettagli completi e i modi in cui possiamo utilizzare gli Scopes.

Documentazione API dell'ambito


7

Gli ambiti non sono altro che metodi di classe.

Perché usarli?

L'ambito consente di specificare query di uso comune (può essere considerato come una scorciatoia per query lunghe o utilizzate più di frequente) a cui è possibile fare riferimento come chiamate di metodo sugli oggetti o modelli di associazione. Con questi ambiti è possibile utilizzare tutti i metodi trattati in precedenza, ad esempio where, join e includes. Tutti i metodi di ambito restituiranno un oggetto ActiveRecord :: Relation che consentirà di chiamare altri metodi (come altri ambiti) su di esso.

Per definire uno scope semplice, usiamo il metodo scope all'interno della classe, passando la query che vorremmo eseguire quando viene chiamato questo scope:

class Article < ActiveRecord::Base
  scope :published, -> { where(published: true) }
end

Questo è esattamente lo stesso che definire un metodo di classe e quello che usi è una questione di preferenze personali:

class Article < ActiveRecord::Base
  def self.published
    where(published: true)
  end
end

Si prega di seguire il seguente collegamento per una descrizione completa con esempio. Spero che questo ti possa aiutare.

http://guides.rubyonrails.org/active_record_querying.html


3
Non è esattamente la stessa cosa che definire un metodo di classe . I metodi di classe restituiscono nilin pochi casi e quindi non concatenabili per determinate condizioni.
Arslan Ali

1
  • Immagina di avere un modello: Persona .

Ora immagina te:

  • voglio tutte le persone nel mondo che hanno i capelli rossi.
  • voglio tutte le persone nel mondo che giocano a cricket

Potresti ottenere quelle particolari classi di persone usando un mirino!

Person.red_hair.cricket ## finds all people with red hair who play cricket
Person.red_hair ## finds all people with red hair
Person.cricket ## finds all people who play cricket.

Non è stato così difficile, vero?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.