Страницы

Поиск по вопросам

пятница, 21 июня 2019 г.

Как правильно организовать базу данных

Столкнулся с такой проблемой. У отелей есть много услуг (например трансфер, парковка, интернет и т.д.), так же у каждой комнаты в отеле могут быть разные услуги (минибар, балкон, вид на море/парк и т.д.). Получается что объект (отель или комната) предоставляют услуги. Связь многие ко многим.
Таблица будет выглядеть примерно так (составной внешний ключ)

А как связать модели?
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
Как правильно это организовать?


Ответ

У вас получается полиморфная связь, которую нужно ввести при помощи ключевого слова 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 - всегда множественное число.
Название таблиц - всегда множественное число, название моделей - всегда единственное число.

Комментариев нет:

Отправить комментарий