Étant donné un modèle avec default_scope pour filtrer toutes les entrées obsolètes:
# == Schema Information
#
# id :integer(4) not null, primary key
# user_id :integer(4) not null, primary key
# end_date :datetime
class Ticket < ActiveRecord::Base
belongs_to :user
default_scope :conditions => "tickets.end_date > NOW()"
end
Maintenant, je veux obtenir tout ticket. Dans ce cas with_exclusive_scope est le chemin à parcourir, mais cette méthode est-elle protégée? Seul cela fonctionne:
Ticket.send(:with_exclusive_scope) { find(:all) }
Une sorte de hack, non? Alors, quelle est la bonne façon d'utiliser? Surtout quand il s'agit d'associations, la situation empire (étant donné qu'un utilisateur a plusieurs tickets):
Ticket.send(:with_exclusive_scope) { user.tickets.find(:all) }
C'est donc laid !!! - ne peut pas être la voie Rails!?
Pour info pour tous ceux qui recherchent la façon de faire Rails3, vous pouvez utiliser la méthode unscoped
:
Ticket.unscoped.all
Évitez default_scope
si possible . Je pense que vous devriez vraiment vous demander à nouveau pourquoi vous avez besoin d'un default_scope
. Contrer un default_scope
est souvent plus compliqué que cela ne vaut et ne devrait être utilisé que dans de rares cas. De plus, en utilisant default_scope
n'est pas très révélateur lorsque les associations de tickets sont accessibles en dehors du modèle de ticket (par exemple "j'ai appelé account.tickets
. Pourquoi mes billets ne sont-ils pas là? "). Cela fait partie des raisons pour lesquelles with_exclusive_scope
est protégé. Vous devriez goûter un peu vinaigre syntaxique lorsque vous devez l'utiliser.
Comme alternative, utilisez un joyau/plugin comme pacecar qui ajoute automatiquement des nom_scopes utiles à vos modèles en vous donnant un code plus révélateur partout. Par exemple:
class Ticket < ActiveRecord::Base
include Pacecar
belongs_to :user
end
user.tickets.ends_at_in_future # returns all future tickets for the user
user.tickets # returns all tickets for the user
Vous pouvez également décorer votre modèle utilisateur pour rendre le code ci-dessus plus propre:
Class User < ActiveRecord::Base
has_many :tickets
def future_tickets
tickets.ends_at_in_future
end
end
user.future_tickets # returns all future tickets for the user
user.tickets # returns all tickets for the user
Remarque: pensez également à utiliser un nom de colonne datetime plus idiomatique, comme ends_at
au lieu de end_date
.
Vous devez encapsuler la méthode protégée dans une méthode de modèle, quelque chose comme:
class Ticket < ActiveRecord::Base
def self.all_tickets_from(user)
with_exclusive_scope{user.tickets.find(:all)}
end
end