#база_данных #ruby_on_rails #activerecord
Столкнулся с такой проблемой. У отелей есть много услуг (например трансфер, парковка, интернет и т.д.), так же у каждой комнаты в отеле могут быть разные услуги (минибар, балкон, вид на море/парк и т.д.). Получается что объект (отель или комната) предоставляют услуги. Связь многие ко многим. Таблица будет выглядеть примерно так (составной внешний ключ) А как связать модели? class Service < ActiveRecord::Base has_many :service_in_object has_many :hotels, through: :service_in_object end class ServiceInObject < ActiveRecord::Base belongs_to :object #хмм belongs_to :service end class Hotel < ActiveRecord::Base has_many :rooms has_many :service_in_object has_many :service, through: :service_in_object end class Room < ActiveRecord::Base belongs_to :hotel has_many :service_in_object has_many :service, through: :service_in_object end Как правильно это организовать?
Ответы
Ответ 1
У вас получается полиморфная связь, которую нужно ввести при помощи ключевого слова polymorphic. Если не возражаете, я немного переделаю таблицу service_in_objects, чтобы избавиться от object - не очень хорошее название, давайте сделаем serviceable. Миграции для таблиц могут выглядеть следующим образом create_table :hotels, comment: "Оттели" do |t| t.string :title, comment: "Название" end create_table :rooms, comment: "Комнаты" do |t| t.string :title, comment: "Номер" t.integer :hotel_id, comment: "Внешний ключ для связи с оттелем" end create_table :services, comment: "Сервисы" do |t| t.string :title, comment: "Название" end create_table :service_in_objects, comment: "Промежуточная cвязующая таблица" do |t| t.integer :service_id, comment: "Внешний ключ для связи с сервисом" t.integer :serviceable_id, comment: "Внешний ключ для связи с оттелем или комнатой" t.string :serviceable_type, comment: "Внешний ключ для связи с оттелем или комнатой" end Тогда модели с учетом полиморфной связи через промежуточную таблицу service_in_objects могут принять следующий вид class Service < ActiveRecord::Base has_many :service_in_objects has_many \ :rooms, through: :service_in_objects, source: :serviceable, source_type: 'Room' has_many \ :hotels, through: :service_in_objects, source: :serviceable, source_type: 'Hotel' end class ServiceInObject < ActiveRecord::Base belongs_to :service belongs_to :serviceable, polymorphic: true end class Hotel < ActiveRecord::Base has_many :rooms has_many :service_in_objects, as: :serviceable, dependent: :destroy has_many :services, through: :service_in_objects end class Room < ActiveRecord::Base belongs_to :hotel has_many :service_in_objects, as: :serviceable, dependent: :destroy has_many :services, through: :service_in_objects end Убедиться в том, что полиморфная связь работает, можно при помощи сидов (db/seed.rb): ActiveRecord::Base.connection.execute('TRUNCATE hotels'); ActiveRecord::Base.connection.execute('TRUNCATE rooms'); ActiveRecord::Base.connection.execute('TRUNCATE services'); ActiveRecord::Base.connection.execute('TRUNCATE service_in_objects'); services = [{title: 'internet'}, {title: 'parking'}, {title: 'service1'}] Service.create services hotels = [{title: 'mariot'}, {title: 'hilton'}] Hotel.create hotels Hotel.all.each do |h| h.rooms.create [{title: '1'}, {title: '2'}, {title: '4'}] h.services << [Service.all.sample, Service.all.sample] h.save end Room.all.each do |r| r.services << [Service.all.sample, Service.all.sample] r.save end В реальном проекте настоятельно рекомендуется покрыть тестами хотя бы связи - у вас примере идущем с вопросом явные ошибки с единственным/множественным числом - тесты вас сильно выручат на данном этапе. Напортачить в связях не сложно, модели будут работать и со сломанными связями, только воспользоваться ими не получится и при этом сообщения об ошибках на сломанных связях не совсем очевидны. Обратите внимание: Связь belongs_to - всегда единственное число, has_many - всегда множественное число. Название таблиц - всегда множественное число, название моделей - всегда единственное число.
Комментариев нет:
Отправить комментарий