Какова цель: условия в ассоциации принадлежат_? - PullRequest
7 голосов
/ 28 января 2010

Скажите, у меня есть следующая связь с приложенным условием:

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.

Документ API заявляет , что опция: condition для assign_to будет:

Укажите условия, при которых связанный объект должен встретиться в порядке быть включенным в качестве WHERE SQL фрагмент, такой как санкционированный = 1.

Но в выводе отсутствует предложение WHERE для выбора, и в любом случае я ожидал бы, что такие условия для объекта own_to будут препятствовать сохранению этой взаимосвязи для начала, для INSERT, а не для SELECT. Эта опция, кажется, не влияет на ассоциацию own_to, если я что-то упустил. Опция имеет смысл для has_many, я просто не понимаю, как она применяется к принадлежащему.

РЕДАКТИРОВАТЬ: Дальнейшие исследования показывают, что вы действительно можете сохранить ассоциацию, которая нарушает условие, но вы не можете получить связанную запись после запись перезагружается.

В классе, определенном так:

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

... из консоли видим:

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

Я связал bloop, который нарушает условие, и сохранил его. Ассоциация сохраняется в БД (см. Bloop_id и big_bloop_id в последней строке выше).

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

То же самое, другой атрибут.

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

Оба недействительных сообщения остаются в памяти.

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

После перезагрузки они исчезли, потому что оператор SELECT действительно использует предложение WHERE для их исключения.

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

И все же виджет все еще имеет ссылки:

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

Мне кажется странным, но вот, пожалуйста.

1 Ответ

4 голосов
/ 28 января 2010

Отличная находка!

Моей первой мыслью было, что это может быть какая-то общая вещь базового класса AssociationProxy или тому подобное. Но копаясь дальше, кажется, есть список конкретных опций, которые принадлежат для разрешения:

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

Так что в какой-то момент подсознательное решение было принято, чтобы поместить это туда. :)

Я не уверен, как вы проверяли ГДЕ, хотя. Мои тесты ясно показывают, что включает предложение 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">

После всего этого мой лог-файл содержит:

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

Пока я пытался напечатать это для вас, я понял, что до сих пор не дал реального ответа на ваш вопрос. :) Я могу думать только об одной причине, чтобы иметь это в ActiveRecord, и это потому, что это не было лишним хлопотом для реализации, и нет никакого смысла в том, чтобы его исключать.

Кто-то может работать над странным крайним случаем с устаревшей базой данных, где золотое правило в офисе - каждый знает сложный путь - никогда не иметь виджет Wookeleywoo, прикрепленный к чему-либо, кроме Jigglymabob.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...