При использовании STI первое чтение для промежуточного подкласса не выполняется, но последующее чтение работает - PullRequest
0 голосов
/ 09 мая 2018

У меня есть модель Rails 4.2, использующая STI, которая терпит неудачу при первой попытке прочитать запись, но успешно в более поздних случаях. Запись имеет тип KbtPrimary, который наследуется от KbTagged, который наследуется от Keybox. Мне нужно выполнить поиск в KbTagged, но запись не найдена при первом чтении в KbTagged. Он обнаруживается, если первое чтение - это Keybox или KbtPrimary.

Упрощенно, код выглядит так:

class Keybox < ActiveRecord::Base
  belongs_to :company
  acts_as_tenant :company
end
class KbTagged < Keybox; end
class KbtPrimary < KbTagged; end
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = Keybox.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"

И вывод такой:

Box:nil;
Box:Automated;
Box:Automated;

Если сначала используется KbtPrimary или Keybox, вывод будет правильным:

box = KbtPrimary.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = Keybox.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = KbtPrimary.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"

Выходы:

Box:Automated;
Box:Automated;
Box:Automated;

SQL для первого неудачного чтения:

"SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."type" IN ('KbTagged') AND "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'"

ДАЛЬНЕЙШЕЕ РЕДАКТИРОВАНИЕ С БОЛЕЕ SQL:

class Keybox < ActiveRecord::Base
  belongs_to :company
  acts_as_tenant :company
end
class KbTagged < Keybox; end
class KbtPrimary < KbTagged; end
puts KbTagged.where(name: 'Automated').to_sql
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
puts Keybox.where(name: 'Automated').to_sql
box = Keybox.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
puts KbTagged.where(name: 'Automated').to_sql
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"

SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."type" IN ('KbTagged') AND "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'
Box:nil;
SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'
Box:Automated;
SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."type" IN ('KbTagged', 'KbtPrimary') AND "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'
Box:Automated;

1 Ответ

0 голосов
/ 10 мая 2018

Проблема в файле config / environment / development.rb со значением:

# Do not eager load code on boot.
config.eager_load = false

Установка этого значения заставляет чтение работать.Однако это не очень полезно в среде разработки.Я продолжаю искать более оптимальное решение, если оно у вас есть.

РЕДАКТИРОВАТЬ: В настоящее время я выдаю требование для классов STI в app / config / initializer, чтобы вместо этого сделать этофорсировать eager_load по всему приложению.На данный момент, я считаю, что влияние будет состоять в том, что эти классы не будут обновляться динамически и потребуют перезапуска сервера для реализации.Я заметил, что может помочь гем, которым является RequireReloader.

ОБНОВЛЕНИЕ: RequireReloader хорошо работает для меня в этом.Для предварительной загрузки классов инициализатор не требуется.

...