views:

248

answers:

1

Say I have the following association with an attached condition:

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.

The API doc states that the :conditions option on belongs_to will:

Specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as authorized = 1.

But the output shows no WHERE clause on the select, and in any case I would expect that conditions like this on a belongs_to would prevent persisting that relationship to begin with, on the INSERT not the SELECT. This option seems to have no effect on a belongs_to association, unless I'm missing something. The option makes sense on a has_many, I just don't see how it applies to belongs_to.

EDIT: Further research reveals that you can indeed persist an association that violates a condition, but you cannot retrieve the associated record after the record is reloaded.

On a class defined like so:

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

...from the console we see:

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

I've associated a bloop that violates the condition and saved it. The association is persisted to the db (see bloop_id and big_bloop_id on the last line above).

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

Same thing, different attribute.

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

Both invalid bloops remain in memory.

>> widget.reload
=> #<Widget id: 2, name: nil, bloop_id: 2, big_bloop_id: 3>
>> widget.bloop
=> nil
>> widget.big_bloop
=> nil

After the reload, they're gone, because the SELECT statement does indeed use a WHERE clause to exclude them.

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

And yet the widget still has the references:

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

Seems odd to me, but there you go.

+3  A: 
Shtééf
Thanks for that, very helpful.
Dave Sims