2009-08-10 5 views
7

Supposons que j'ai une portée nommée:Vérifiez si l'instance de modèle se situe dans named_scope dans des rails

class Foo < ActiveRecord::Base 
    named_scope :bar, :conditions => 'some_field = 1' 
end 

Cela fonctionne très bien pour les requêtes et j'ai un tas de named_scopes utiles définies. Qu'est-ce que je voudrais est de pouvoir faire ceci:

f = Foo.find(:first) 
f.some_field = 1 
f.is_bar? #=> true 

Le '.bar?' La méthode retournera simplement true ou false si l'instance de modèle tombe dans la portée nommée. Est-il possible de le faire sans écrire un 'is_bar?' méthode même si j'ai déjà écrit un bon moyen de vérifier si quelque chose «is_bar? Si je me souviens bien, DRY est bon donc toute aide serait grandement appréciée/

Répondre

20

Vous pouvez appeler la méthode exists? sur une étendue nommée qui interrogera la base de données pour voir si l'enregistrement donné existe avec ces conditions.

Foo.bar.exists?(f) 

Cependant, cela ne fonctionnera pas si vous avez modifié les attributs sur f et non enregistré sur la base de données. Cela est dû au fait que les conditions d'étendue nommées sont SQL, de sorte que la vérification doit se produire à cet endroit. Tenter de convertir en conditions Ruby if est désordonné, en particulier dans des scénarios plus complexes.

+0

merci. Ok, fais comme si j'appelais .save après avoir changé la valeur. Foo.bar.exists? (Foo.find (: first)) retournera vrai ou faux selon qu'il se situe dans la portée de la barre? Impressionnant. – user94154

+0

Correct. Vous ne devriez pas avoir à appeler à nouveau Find non plus. "f.save; Foo.bar.exists? (f)" devrait fonctionner. – ryanb

+4

Est-ce que cela a été plus facile depuis 2009? –

1

Si vos étendues sont simples, vous voulez probablement éviter la duplication de code. Ma solution vous permet d'appeler model.active? pour savoir si une instance appartient à la portée, et Model.active pour trouver tous les enregistrements correspondant à la portée. model.active? n'implique aucune requête de base de données.

Pensez à ajouter à ce config/initializers/scope_and_method.rb:

require 'active_record/named_scope' 

module ActiveRecord::NamedScope::ClassMethods 
    def scope_and_method field, *values 
    field = field.to_sym 
    values.each do |value| 
     named_scope value.to_sym, :conditions => {field => value} 
     define_method "#{value}?" do 
     send(field.to_sym) == value 
     end 
    end 
    end 
end 

Utilisation:

scope_and_method :state, 'active', 'inactive' 

Works comme si elle était:

named_scope :active, :conditions => {:state => 'active'} 
named_scope :inactive, :conditions => {:state => 'inactive'} 

def active? 
    state == 'active' 
end 

def inactive? 
    state == 'inactive' 
end 

Ceci est une solution pour Rails 2.3. Cela nécessite un très petit réglage pour Rails 3 et 4. (named_scope ->scope) Je vais le vérifier bientôt.

Questions connexes