2015-03-27 2 views
1

Je ne comprends pas comment cette méthode fonctionne dans ce cas:Comment fonctionne la méthode `extending 'dans ActiveRecord?

def self.page(page) 
    limit(default).offset(page * default).extending do 
    def per(num) 
    limit(num).offset(page * num) 
    end 
end 

Il est un peu différent de the original code.

Nous pouvons utiliser ModelName.page(1).per(5). Je suis vraiment confus au sujet de comment cela fonctionne. On dirait que de la magie est arrivée.

+0

où vous avez trouvé le code que vous avez mentionné dans votre question? –

+0

Vérifiez le lien dans ma question. Mon code est une version simple de l'original. De kaminari gem. – duykhoa

+1

S'il vous plaît _notify_ moi si vous ne comprenez pas encore de partie .. Je vais essayer de vous aider.,. –

Répondre

2

Comme extending disant -

Utilisé pour étendre la portée des méthodes supplémentaires, soit par un module ou par un bloc fourni. L'objet renvoyé est une relation qui peut être étendue.

Voici un petit exemple pour illustrer cette fonctionnalité:

Spree::Order.class_eval do 
    def self.scope_cart 
    self.where(currency: "INR").extending do 
     def orders_in_cart 
     where.not(state: 'cart') 
     end 
    end 
    end 
end 

Spree::Order.scope_cart.count # => 367 
# SQl code 
# SELECT COUNT(*) FROM "spree_orders" WHERE "spree_orders"."currency" = 'INR' 
Spree::Order.count # => 367 

Jusqu'à présent, vous pouvez voir que le scope_cart me donne le nombre de données qui est le résultat de self.where(currency: "INR"). Eh bien, voyons maintenant ce que nous donne la nouvelle méthode orders_in_cart.

Spree::Order.scope_cart.orders_in_cart.count # => 342 
# SQL code 
# SELECT COUNT(*) FROM "spree_orders" WHERE "spree_orders"."currency" = 'INR' AND ("spree_orders"."state" != 'cart') 

Note: S'il vous plaît noter le code SQL, pour 2 cas différents. Il y a la réponse à votre question.

Maintenant, revenons à votre exemple. Quand vous appellerez ModelName.page(1), vous obtiendrez le résultat de cette limit(default).offset(page * default). Maintenant si vous voulez le filtrage supplémentaire, vous appelez la méthode per comme ModelName.page(1).per(5), alors vous obtiendrez le résultat de limit(num).offset(page * num), qui est appliqué sur le résultat de .

Son extension encore plus:

Quand vous faites ModelName.page(1), limit prend le par défaut par valeur, avec offset comme 1 * default. Équivalent SQL est -

SELECT "model_names".* FROM "model_names" LIMIT 20 OFFSET 20 

Lorsque vous faites ModelName.page(1).per(5), limit prend le 5 selon la valeur, avec offset comme 1 * 5. Équivalent SQL est -

SELECT "model_names".* FROM "model_names" LIMIT 5 OFFSET 5 

Dans Rails, je vis dans la documentation si vous écrivez comme User.limit(10).limit(20), il génère SQL a LIMIT 20, signifie qu'il prend la dernière limit clause de la chaîne. La même chose est true pour le offset.

Regardez la console SQL généré Code:

Spree::Order.limit(20).offset(2).limit(5).offset(5) 
# Spree::Order Load (0.5ms) SELECT "spree_orders".* FROM "spree_orders" LIMIT 5 OFFSET 5 
+0

Donc, nous pouvons utiliser cette méthode pour une Relation seulement, et le résultat sera une relation. Est-ce la même chose avec '' result = Spree :: Order.limit (3) \ n class << résultat \ n def per (num) .... '' – duykhoa

+1

@duykhoa Non c'est surtout comme [ceci] (http: //ruby-doc.org/core-2.2.1/Object.html#method-i-extend). –

+0

Comprenez, c'est une utilisation anticipée. Mais ça a l'air plutôt génial. – duykhoa