Qu'est-ce que scope / named_scope dans les rails?


106

J'ai récemment commencé un stage. Mon employeur utilise ruby ​​on rails et je rencontre souvent une nouvelle syntaxe que je dois rechercher pour comprendre. J'ai cherché sur Google une bonne explication de named_scope, mais ce que j'ai trouvé jusqu'à présent, ce sont principalement des articles de blog qui en font l'éloge, plutôt une définition ou une introduction simple.

Qu'est-ce que named_scope (maintenant simplement appelé scope) dans ruby ​​on rails?



2
Ce billet de blog a été inestimable pour moi lors de l'apprentissage des portées nommées: ryandaigle.com/articles/2008/8/20/…
Peter Brown

@notapatch le lien est mort en avez-vous un autre?
mbigras

Ryan Daigle: Nommée Portée: Il ne suffit pas pour les conditions, Ya Know de web.archive.org/web/20160306110506/http://...
notapatch

Réponses:


213

Une étendue est un sous-ensemble d'une collection. Cela semble compliqué? Ça ne l'est pas. Imagine ça:

Vous avez des utilisateurs. Désormais, certains de ces utilisateurs sont abonnés à votre newsletter. Vous avez marqué ceux qui reçoivent une newsletter en ajoutant un champ à la base de données des utilisateurs (user.subscribed_to_newsletter = true). Naturellement, vous souhaitez parfois obtenir les utilisateurs qui sont abonnés à votre newsletter.

Vous pouvez, bien sûr, toujours faire ceci:

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

Au lieu de toujours écrire ceci, vous pouvez cependant faire quelque chose comme ceci.

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

Si vous utilisez Rails 4 ou plus récent , procédez comme suit:

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

Cela vous permet d'accéder à vos abonnés en faisant simplement ceci:

User.newsletter.each do #something

Ceci est un exemple très simple, mais en général, les portées peuvent être des outils très puissants pour faciliter votre travail.

Consultez ce lien: Description de l'API


7
Puis-je demander quels sont les avantages de cela par rapport à la définition d'une méthode dans la classe d'utilisateurs appelée «abonnés abonnés»? par exemple 'def self.subscribedUsers self.where (: subscribed_to_newsletter => true) end
redroot

3
@redroot l'avantage est que la scopesyntaxe est beaucoup plus propre, vous obtenez le même résultat mais avec une seule ligne
Aldo 'xoen' Giambelluca

9
@redroot Il y avait autrefois un gros avantage en termes d'efficacité, car les scopes interrogeaient la base de données paresseusement tandis que les méthodes le faisaient avec empressement. Dans Rails 3, les méthodes sont également devenues paresseuses, donc maintenant la différence est plus syntaxique. Source
evanrmurphy

Le lien vers la documentation de l'API est rompu, veuillez mettre à jour api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/…
Lohith MV

Permet également d'utiliser le lien des
Benjineer

34

La portée dans l'enregistrement actif est comme les méthodes de classe, mais elles renvoient un objet Relation, ce qui signifie que vous pouvez appeler une autre portée ou une autre méthode d'interrogation d'enregistrement actif dessus.

Par exemple, si vous avez un modèle Zombie (table zombies) avec les méthodes de portée mentionnées ci-dessous,

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

Et tu appelles

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

Cela se traduit par ce qui suit en SQL,

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

L'exemple ci-dessus est basé sur la syntaxe de rails 4


Je ne trouve pas d'exemple d'ordre (: created_at,: desc) dans aucune documentation. Est-ce possible que vous vouliez dire scope :recent, -> { order(created_at: :desc) }? apidock.com/rails/v4.2.9/ActiveRecord/QueryMethods/order
notapatch le

7

La meilleure façon de comprendre les détails est d'accéder à la documentation de l'API.

Vous obtiendrez tous les détails et la manière dont nous pouvons utiliser Scopes.

Documentation API de la portée


7

Les portées ne sont rien d'autre que des méthodes de classe.

Pourquoi les utiliser?

La portée vous permet de spécifier des requêtes couramment utilisées (elle peut être considérée comme un raccourci pour les requêtes longues ou les plus fréquemment utilisées) qui peuvent être référencées comme des appels de méthode sur les objets ou modèles d'association. Avec ces étendues, vous pouvez utiliser toutes les méthodes précédemment couvertes telles que where, join et includes. Toutes les méthodes d'étendue renverront un objet ActiveRecord :: Relation qui permettra d'appeler d'autres méthodes (telles que d'autres étendues).

Pour définir une portée simple, nous utilisons la méthode scope à l'intérieur de la classe, en passant la requête que nous aimerions exécuter lorsque cette portée est appelée:

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

C'est exactement la même chose que la définition d'une méthode de classe, et que vous utilisez est une question de préférence personnelle:

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

Veuillez suivre le lien suivant pour une description complète avec un exemple. J'espère que cela t'aidera.

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


3
Ce n'est pas exactement la même chose que la définition d'une méthode de classe . Les méthodes de classe retournent nildans quelques cas, et ne peuvent donc pas être chaînées dans certaines conditions.
Arslan Ali

1
  • Imaginez que vous ayez un modèle: Person .

Imaginez maintenant:

  • veulent tous les gens dans le monde qui ont les cheveux roux.
  • veulent tous les gens du monde qui jouent au cricket

Vous pouvez obtenir ces classes particulières de personnes en utilisant une portée!

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.

Ce n'était pas si difficile, n'est-ce pas?

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.