web-dev-qa-db-fra.com

Rails: Pourquoi with_exclusive_scope est-il protégé? Une bonne pratique sur la façon de l'utiliser?

É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!?

46
RngTng

Pour info pour tous ceux qui recherchent la façon de faire Rails3, vous pouvez utiliser la méthode unscoped:

Ticket.unscoped.all
173
brad

É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.

34
Ryan McGeary

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
20
Vlad Zloteanu