2010-01-28 3 views
7

Dire que j'ai l'association suivante avec une condition attachée:Quel est l'objectif de: conditions sur une association belongs_to?

belongs_to :admin_user, 
    :class_name => 'User', 
    :foreign_key => :admin_user_id, 
    :conditions=> 'users.admin=TRUE' # or any variation with hash or array, {:admin => true}, etc. 

Le API doc states que: conditions option belongs_to seront:

Spécifiez les conditions que l'objet associé doit satisfaire à inclure en tant que fragment WHERE SQL , tel que autorisé = 1.

Mais la sortie ne montre aucune clause WHERE sur le select, et dans tous les cas je m'attendrais à ce que des conditions comme celle-ci sur un belongs_to empêchent la poursuite de cette relation, sur l'INSERT et pas sur le SELECT. Cette option semble n'avoir aucun effet sur une association belongs_to, à moins de manquer quelque chose. L'option a du sens sur un has_many, je ne vois tout simplement pas comment cela s'applique à belongs_to.

EDIT: D'autres recherches révèlent que vous pouvez en effet persister une association qui enfreint une condition, mais vous ne pouvez pas récupérer l'enregistrement associé après l'enregistrement est rechargé.

Sur une classe définie comme ceci:

class Widget < ActiveRecord::Base 

    belongs_to :big_bloop, 
     :class_name => "Bloop", 
     :foreign_key => :big_bloop_id, 
     :conditions => ["big_bloop = ?", true] 

    belongs_to :bloop, :conditions => ["big_bloop = ?", true] 

end 

... à partir de la console, nous voyons:

>> bloop = Bloop.new 
=> #<Bloop id: nil, name: nil, big_bloop: nil> 
>> widget = Widget.new 
=> #<Widget id: nil, name: nil, bloop_id: nil, big_bloop_id: nil> 
>> widget.bloop = bloop 
=> #<Bloop id: nil, name: nil, big_bloop: nil> 
>> widget.save! 
=> true 
>> widget 
=> #<Widget id: 2, name: nil, bloop_id: 2, big_bloop_id: nil> 

J'ai associé un bloop qui viole la condition et l'a sauvé. L'association est conservée dans la base de données (voir bloop_id et big_bloop_id sur la dernière ligne ci-dessus).

>> big_bloop = Bloop.new 
=> #<Bloop id: nil, name: nil, big_bloop: nil> 
>> widget.big_bloop = big_bloop 
=> #<Bloop id: nil, name: nil, big_bloop: nil> 
>> widget.save! 
=> true 
>> widget 
=> #<Widget id: 2, name: nil, bloop_id: 2, big_bloop_id: 3> 

Même chose, attribut différent.

>> widget.bloop 
=> #<Bloop id: 2, name: nil, big_bloop: nil> 
>> widget.big_bloop 
=> #<Bloop id: 3, name: nil, big_bloop: nil> 

Les deux bloops invalides restent en mémoire. Après le rechargement, ils ont disparu, car l'instruction SELECT utilise en effet une clause WHERE pour les exclure.

Bloop Load (0.3ms) SELECT * FROM `bloops` WHERE (`bloops`.`id` = 2 AND (big_bloop = 1)) 

Et pourtant, le widget a encore les références:

>> widget 
=> #<Widget id: 2, name: nil, bloop_id: 2, big_bloop_id: 3> 

semble étrange pour moi, mais là vous allez.

Répondre

4

C'est une bonne trouvaille! Ma première pensée était que cela pourrait être quelque chose de générique de la classe de base AssociationProxy ou similaire. Mais creuser plus bas, il semble y avoir une liste d'options spécifiques belongs_to permet:

@@valid_keys_for_belongs_to_association = [ 
    :class_name, :primary_key, :foreign_key, :foreign_type, :remote, :select, :conditions, 
    :include, :dependent, :counter_cache, :extend, :polymorphic, :readonly, 
    :validate, :touch 
] 

Donc, à un moment donné, la décision peut-être inconscient a été fait pour qu'il y mettre. :)

Je ne sais pas comment vous avez testé le WHERE, cependant.Mon test montre clairement fait comprennent la clause WHERE:

class Thing < ActiveRecord::Base; end 

class Widget < ActiveRecord::Base 
    belongs_to :thing, :conditions => ['name = ?', 'Jigglymabob'] 
end 

Thing.create :name => 'Jigglymabob' 
# => #<Thing id: 1, name: "Jigglymabob"> 
w = Widget.create :name => 'Wookeleywoo', :thing_id => 1 
# => #<Widget id: 1, name: "Wookeleywoo", thing_id: 1> 
w.thing 
# => #<Thing id: 1, name: "Jigglymabob"> 

Après tout cela, mon fichier journal contient:

Thing Create (0.3ms) INSERT INTO "things" ("name") VALUES('Jigglymabob') 
Widget Create (0.3ms) INSERT INTO "widgets" ("name", "thing_id") VALUES('Wookeleywoo', 1) 
Thing Load (0.6ms) SELECT * FROM "things" WHERE ("things"."id" = 1 AND (name = 'Jigglymabob')) 

Comme je suis en train et en tapant ce pour vous, je me suis rendu Je n'ai toujours pas donné une vraie réponse à votre question. :) Je ne peux penser à une seule raison d'avoir cela dans ActiveRecord, et c'est parce que ce n'était pas un problème supplémentaire à implémenter, et il n'y a aucun avantage à le laisser de côté.

Quelqu'un là-bas peut travailler sur une affaire de bord étrange avec une base de données existante, où la règle d'or dans le bureau — que tout le monde apprend la dure — est de ne jamais avoir un widget Wookeleywoo attaché à quoi que ce soit autre qu'un Jigglymabob.

+0

Merci pour cela, très utile. –

Questions connexes