2012-12-01 1 views
2

J'ai un modèle utilisateur dans lequelPourquoi User.last (2) et User.first (2) retournent les mêmes utilisateurs?

default_scope :order => 'created at desc' 

J'ai actuellement cinquante dossiers, ids 1 à 50.

User.first retours User id: 50.

User.first(2) retours User id: 50 et User id: 49

User.last retours User id: 1

Tout cela est logique. Cependant,

User.last(2) renvoie User id: 49 et User id: 50, dans cet ordre. Pourquoi donc? Et comment puis-je retourner User id: 1 et User id: 2?

+0

remplacez le domaine: order => 'created_at asc' –

+0

Merci @Jani. Je souhaite conserver l'ordre par défaut tel qu'il est, car je souhaite que mon index reste inchangé.Cependant, je veux être en mesure d'accéder à des groupes d'utilisateurs du "haut" et du "bas" de la liste en utilisant la console, au cas où je devrais faire des mises à jour de groupe. Quelle est la meilleure façon de faire cela? – umezo

+1

vous pouvez créer une deuxième portée create_asc unscoped.order ('created_at asc), puis utiliser User.create_asc.limit (2). Pouvez-vous fournir des requêtes sql qui ont été exécutées dans les deux cas? – sufleR

Répondre

3

Ceci est une erreur courante. User.last(1) et User.last() ne sont pas exactement les mêmes. User.last(1) vous donnerait un tableau d'un seul enregistrement tandis que User.last() retournerait cet objet d'enregistrement.

Encore une fois, ces deux méthodes se comporteraient différemment si vous avez un default_scope dans votre modèle utilisateur. Fonctionne simplement sur votre portée par défaut, en inversant son ordre

Ainsi, la requête SQL il se déclenche est:

SELECT * FROM users ORDER BY created_at ASC LIMIT 1 

D'autre part, User.last(1) est similaire à l'écriture User.order('id desc').limit(1). Et avec votre default_scope en action, le order by id desc viendrait en second par défaut. Ainsi, le SQL il se déclenche serait:

SELECT * FROM users ORDER BY created_at desc, id desc LIMIT 1 

Donc ce que vous avez vraiment besoin de faire ici est de supprimer la portée par défaut en utilisant User.unscoped comme Kien a mentionné. Personnellement, j'évite d'utiliser l'ordre de portée par défaut et j'utilise à la place une portée explicite.

+0

Merci beaucoup @atmash pour la réponse détaillée. Donc, la réponse est de désappliquer, puis interroger le 'first (2)', car ils sont maintenant classés par id. – umezo

+1

Pas exactement. le premier (N) et le dernier (N) montrent également un comportement différent. User.last (2) trierait par 'id desc' et retournerait les 2 meilleurs résultats (49 et 50 dans votre cas). Mais User.first (2) renvoie les deux premiers enregistrements renvoyés par la base de données et n'applique aucun ordre de tri explicite dans le SQL. Les chances sont que vous obtiendrez l'utilisateur avec l'ID 1 et 2 mais vous ne pouvez pas compter dessus. Je suggère d'utiliser User.unscoped.order (: id) .first (2) – atmaish

+0

Merci @atmaish. Je me suis dit que «pas de portée par défaut == ordonnée par id», et c'était le vrai dans ce cas pour moi, mais je suppose qu'il est plus sûr de dire explicitement 'order (: id)'. – umezo

1

Rubydocs vous donne des informations sur la première et la dernière méthode.

Si vous dernier (2) ne fonctionne pas, vous pouvez essayer

User.find(:order => 'created_at asc', :limit =>2) 

corrigé

User.find(:all,:order => 'created_at asc', :limit =>2) 
User.unscoped.order('created_at asc').limit(2) 

Vous pouvez y passer beaucoup d'arguments pour obtenir ce que vous voulez.

+0

C'est faux! Cela n'a aucun sens d'utiliser l'option limit avec la méthode Model.first(). 'first' ajoute implicitement limit = 1 au sql. Donc: limite => 2 serait ignoré dans votre cas. – atmaish

+0

@atmaish Vous avez raison. Il devrait être trouvé au lieu de premier. Réponse corrigée – sufleR

+0

Merci @sufleR, mais votre suggestion retourne 'ActiveRecord :: RecordNotFound: impossible de trouver l'utilisateur sans ID '. La solution avec laquelle je suis allé est 'User.unscoped.first (2)'. – umezo

1

Essayez la méthode unscoped:

User.unscoped.first(2) # Get User id=1 and id=2 

Vous pouvez vérifier Remove all scoping.

+0

Merci @Kien. Il s'avère que c'est en fait 'User.unscoped.first (2)', car il est maintenant ordonné par id, et les identifiants 1 et 2 viennent maintenant au début. – umezo

+1

oh, j'ai vu dans votre question 'User.last (2) renvoie l'ID de l'utilisateur: 49 et l'id de l'utilisateur: 50' :)), laissez-moi mettre à jour la réponse. – Thanh

Questions connexes