Rails STI: как изменить сопоставление между именем и значением класса столбца типа
Из-за правил компании я не могу использовать наши имена классов домена; Вместо этого я буду использовать аналогию. У меня есть таблица под названием проекты, в которой есть столбец с названием "тип" с возможными значениями как "закрытый" и "открытый". Записи, имеющие внутренний и наружный, имеют четкое разделение функций и будут довольно аккуратно использоваться в качестве реализации ИППП. К сожалению, я не могу изменить имена типов и не могу добавлять классы в глобальное пространство имен. Есть ли способ указать другое значение для "type"?
Примечание. Я не пытаюсь использовать другое имя столбца вместо "type" для STI. Я ищу, чтобы иметь другое значение для типа, кроме имени моего класса.
Ответы
Ответ 1
Вы можете попробовать что-то вроде этого:
class Proyect < ActiveRecord::Base
end
Затем класс Indoor, но с другим именем
class Other < Proyect
class << self
def find_sti_class(type_name)
type_name = self.name
super
end
def sti_name
"Indoor"
end
end
end
То же самое относится к классу Outdoor.
Вы можете проверить sti_name в http://apidock.com/rails/ActiveRecord/Base/find_sti_class/class
Ответ 2
Это возможно, но немного запутанно. По сути, когда вы сохраняете запись унаследованного класса, метод перемещается к родительскому классу с добавленным значением типа.
Стандартное определение:
class Vehicle < ActiveRecord::Base
..
def type=(sType)
end
..
end
class Truck < Vehicle
# calling save here will trigger a save on a vehicle object with type=Truck
end
Изменение, на мой взгляд, в лучшем случае нестабильно. Вероятно, вы столкнетесь с другими проблемами.
Недавно я обнаружил AR-метод becomes, который должен позволить вам преобразовывать дочерние объекты в родительские объекты или как документация предлагает родителям детей, вам может быть повезло с этим.
vehicle = Vehicle.new
vehicle = vehicle.becomes(Truck) # convert to instance from Truck to Vehicle
vehicle.type = "Truck"
vehicle.save!
Не использовать это сам, но просто, вы должны иметь возможность изменить значение столбца type
перед сохранением довольно легко. Это, вероятно, вызовет несколько проблем с встроенным интерфейсом запросов и ассоциаций Active Record.
Кроме того, вы можете сделать что-то вроде:
class Truck
..
def self.model_name
"MyNewClassName"
end
..
end
Но при таком подходе будьте осторожны, что остальные рельсы, включая маршруты и контроллеры, будут относиться к модели как "MyNewClassName", а не "Грузовик".
PS: Если вы не можете добавлять классы внутри своего глобального пространства имен, то почему бы не добавить их в другое пространство имен? Родитель и ребенок могут принадлежать к разным пространствам имен или могут принадлежать к уникальному пространству имен (а не глобальному).
Ответ 3
Если требуется только удаление имен модулей из поля type
, можно использовать следующий вспомогательный модуль, основанный на ответе VAIRIX:
# lib/util/namespaceless_sti.rb
module NamespacelessSti
def find_sti_class(type_name)
type_name = self.name
super
end
def sti_name
self.name.sub(/^.*:/,"")
end
end
Этот модуль должен быть расширен в каждый базовый класс STI, например. Project
из описания OP (воображаемые модели живут в Acme
пространстве имен/модуле)
# app/models/acme/project.rb
require "util/namespaceless_sti"
module Acme
class Project < ActiveRecord::Base
extend NamespacelessSti
end
end
# app/models/acme/indoor.rb
module Acme
class Indoor < Project
# nothing special needs to be done here
end
end
Это гарантирует, что записи Acme::Indoor
в таблице projects
будут иметь "закрытый" в поле type
.
Ответ 4
При взгляде на исходный код, кажется, есть опция store_full_sti_class
(я не знаю, когда она была введена):
config.active_record.store_full_sti_class = false
Это избавит меня от модулей namespacing для меня в Rails 4.2.7