Полиморфные отношения Rails

#ruby-on-rails #ruby #orm #ruby-on-rails-5

#ruby-on-rails #ruby #orm #ruby-on-rails-5

Вопрос:

Я пытаюсь использовать полиморфные отношения с rails 5.

Мне трудно понять, как завершить мои отношения.

У меня есть пользователи, которые могут бронировать отели, рестораны и т.д.

Моя цель — получить название отеля и бронирование при вызове / users / {id} через API.

Вот моя пользовательская модель :

 class User < ApplicationRecord
     has_many :reservations, as: :reservable
     has_many :hotels, through: :reservations
end
  

Моя модель отеля :

 class Hotel < ApplicationRecord
      has_many :reservations, as: :reservable
      belongs_to :users, through: :reservations
end
  

Моя модель резервирования :

 class Reservation < ApplicationRecord
      belongs_to :reservable, polymorphic: true
      belongs_to :users
      belongs_to :hotels
end
  

Миграции :

Пользователь :

 class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :first_name
      t.string :last_name
      t.string :email

      t.timestamps
    end
  end
end
  

Оговорки :

 class CreateReservations < ActiveRecord::Migration[5.0]
  def change
    create_table :reservations do |t|
      t.belongs_to :hotel, index: true
      t.belongs_to :user, index: true
      t.datetime :date_from
      t.datetime :date_to

      t.timestamps
    end
  end
end
class ReservationPolymorphism < ActiveRecord::Migration[5.0]
  def change
      rename_column :reservations, :hotel_id, :reservable_id
      change_column :reservations, :reservable_id, polymorphic: true
      add_column :reservations, :reservable_type, :string
  end
end
  

Гостиница :

 class CreateHotels < ActiveRecord::Migration[5.0]
  def change
    create_table :hotels do |t|
      t.string :name
      t.string :address
      t.string :postal_code
      t.string :town

      t.timestamps
    end
  end
end
  

У меня есть только 1 строка в моей таблице резервирования :

 mysql> select * from reservations;
 ---- --------------- ----------------- --------- --------------------- --------------------- --------------------- --------------------- 
| id | reservable_id | reservable_type | user_id | date_from           | date_to             | created_at          | updated_at          |
 ---- --------------- ----------------- --------- --------------------- --------------------- --------------------- --------------------- 
|  1 |             1 | Hotel           |       1 | 2017-01-12 00:00:00 | 2017-01-15 00:00:00 | 2016-10-19 09:18:01 | 2016-10-19 09:18:01 |
 ---- --------------- ----------------- --------- --------------------- --------------------- --------------------- --------------------- 
  

У меня нет результата при использовании API.

Вот что я получаю, используя консоль Rails :

 2.2.3 :001 > thomas = User.find(1)
  User Load (0.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
 => #<User id: 1, first_name: "Thomas", last_name: "Dupont", email: "thomas.dupont@yopmail.com", created_at: "2016-10-18 21:12:12", updated_at: "2016-10-18 21:12:12"> 
2.2.3 :003 >   thomas.reservations
  Reservation Load (0.3ms)  SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`reservable_id` = 1 AND `reservations`.`reservable_type` = 'User'
2.2.3 :005 > thomas.hotels
NameError: uninitialized constant User::Hotels
  

Итак, я вижу, что совершаю основную ошибку с отношениями rails и полиморфизмом, но я действительно не могу понять, где я ошибаюсь.

Я думаю, что допустил ошибку. Я предположил, что полиморфизм может использоваться для загрузки других моделей и их таблиц (например, «MorphTo» с помощью eloquent / laravel), тогда как это просто для загрузки модели, которая не имеет представления данных (как описано в этом сообщении :https://robots.thoughtbot.com/using-polymorphism-to-make-a-better-activity-feed-in-rails )

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

1. Не могли бы вы, пожалуйста, удалить дополнительные ассоциации, написанные в моделях User и Hotel. пожалуйста, удалите следующее: ‘has_many :hotels, через: :reservations’ из User и ‘belongs_to :users, через: :reservations’ из Hotel. а затем запустите запросы в консоли

2. Только что сделал это и все еще получил проблему «Выбор загрузки резервирования (0,4 мс) reservations .* ИЗ reservations ГДЕ reservations . reservable_id = 1 И reservations . reservable_type = ‘User’ => #<ActiveRecord::Associations::CollectionProxy []> «.

3. не могли бы вы, пожалуйста, удалить это тоже из модели бронирования, belongs_to:пользователи, belongs_to: отели

4. Все равно получаем тот же результат. Я думаю, что проблема в том, что я использую отношения «неправильным способом», поскольку он ищет тип «Пользователь» в таблице резервирования, тогда как я хочу, чтобы он загружал бронирование отелей.

5. Не могли бы вы также добавить файлы миграции? из вышеупомянутых моделей?

Ответ №1:

Я предполагаю, что при просмотре вашего кода вы написали дополнительные ассоциации поверх полиморфной ассоциации,

Для создания полиморфной ассоциации достаточно просто следующего кода. Нет необходимости передавать дополнительную ассоциацию внутри модели. Пожалуйста, измените свой код следующим образом, модель пользователя

 class User < ApplicationRecord
     has_many :reservations, as: :reservable
end
  

Модель отеля :

 class Hotel < ApplicationRecord
      has_many :reservations, as: :reservable
end
  

Модель резервирования :

 class Reservation < ApplicationRecord
      belongs_to :reservable, polymorphic: true
end
  

И в файле миграции для резервирования добавьте резервируемый, как показано ниже

 t.references :reservable, polymorphic: true
  

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

1. Хорошо, я получил первую ошибку, которую я делаю: пользователь не резервируется. Пользователь имеет множество резервирований через отношения user_id, а не «reservable_id». Я должен выяснить отношение user -> hotels, чтобы оно полностью работало.

2. Он продолжает искать «2.2.3:001 > u = User.find (1) Загрузка пользователя (0,5 мс) ВЫБЕРИТЕ users .* ИЗ users ЧЕГО users . id = 1 ОГРАНИЧЕНИЕ 1 => #<Идентификатор пользователя: 1, имя пользователя: «Thomas», фамилия: «Dupont», электронная почта: «thomas.dupont@yopmail.com «, created_at: «2016-10-18 21:12:12», updated_at: «2016-10-18 21:12:12»> 2.2.3 :002 > u.загрузка резервирования (0,4 мс) ВЫБЕРИТЕ reservations .* ИЗ reservations ГДЕ reservations . reservable_id = 1 И reservations . reservable_type = ‘User’ => #<ActiveRecord::Associations::CollectionProxy []> «. Это не то поведение, которое я ищу.

Ответ №2:

Хорошо, я разобрался с этим :

Это модель резервирования :

 class Reservation < ApplicationRecord
      belongs_to :reservable, polymorphic: true
end
  

Это модель отеля :

 class Hotel < ApplicationRecord
end
  

И пользовательская модель :

 class User < ApplicationRecord
     has_many :reservations
end
  

И как я получил результаты в консоли rails :

 Running via Spring preloader in process 87452
Loading development environment (Rails 5.0.0.1)
2.2.3 :001 > u = User.find(1)
  User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
 => #<User id: 1, first_name: "Thomas", last_name: "Dupont", email: "thomas.dupont@yopmail.com", created_at: "2016-10-18 21:12:12", updated_at: "2016-10-18 21:12:12"> 
2.2.3 :002 > u.reservations
  Reservation Load (0.3ms)  SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`user_id` = 1
 => #<ActiveRecord::Associations::CollectionProxy [#<Reservation id: 1, reservable_id: 1, reservable_type: "Hotel", user_id: 1, date_from: "2017-01-12 00:00:00", date_to: "2017-01-15 00:00:00", created_at: "2016-10-19 09:18:01", updated_at: "2016-10-19 09:18:01">]> 
2.2.3 :003 > u.reservations.first.reservable
  Hotel Load (0.3ms)  SELECT  `hotels`.* FROM `hotels` WHERE `hotels`.`id` = 1 LIMIT 1
 => #<Hotel id: 1, name: "HYATT REGENCY HOTEL", address: "3 Place du Général Kœnig", postal_code: "75017", town: "PARIS", created_at: "2016-10-19 08:36:55", updated_at: "2016-10-19 08:36:55">