Самоференциальные ассоциации в Rails 5 - PullRequest
0 голосов
/ 12 января 2019

Я пытаюсь установить самоссылочную ассоциацию в Rails 5. У меня есть модель видео. Видео может иметь предыдущее видео (как в сериале). В идеале это будет выглядеть так:

irb(main):001:0> first_video  = Video.create(url: 'https://youtu.be/W0lhlPdo0mw')
irb(main):002:0> second_video = Video.create(url: 'https://youtu.be/gQhlw6F603o', previous_video: first_video)
irb(main):003:0> second_video.previous_video
=> #<Video id: 1, url: "https://youtu.be/W0lhlPdo0mw">

Это мой текущий подход, но он не работает с (PG::UndefinedColumn: ERROR: column videos.video_id does not exist), поэтому я должен передать идентификатор.

Модель

class Video < ApplicationRecord
  has_one :previous_video, class_name: 'Video'
end

Миграция

class CreateVideo < ActiveRecord::Migration[5.2]
  def change
    create_table :videos do |t|
      t.string :url, null: false
      t.references :previous_video, class: 'Video'

      t.timestamps
    end
  end
end

Какая лучшая практика для достижения этого в Rails 5? И почему вышеупомянутое не работает как ожидалось? Команда Cheers!

Ответы [ 2 ]

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

t.references предназначен для belongs_to ассоциаций в модели и has_one в связанной модели. Ниже я бы написал модель и миграцию, чтобы выполнить то, что вы хотите.

Обновление (2019-05-31):

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

# model
class Video < ApplicationRecord
  belongs_to(
    # by default, the association name + "_id" will be used for the column name
    :next_video,
    optional: true,
    class_name: 'Video', # will use the table of the specified model
    inverse_of: :previous_video
  )

  has_one(
    :previous_video,
    class_name: 'Video', # will use the table of the specified model
    foreign_key: 'next_video_id',
    inverse_of: :next_video
  )
end

# migration
class CreateVideo < ActiveRecord::Migration[5.2]
  def change
    create_table(:videos) do |t|
      t.string(:url, null: false)

      # This will create a `next_video_id` column. Add/remove any options as you
      # see fit.
      # - index: creates an index on the column
      t.references(:next_video, index: true)

      t.timestamps
    end

    # A foreign key could have been created when specifying the `references`
    # column inside `create_table`, but it's self referential, and I'm not sure
    # if it would work. So to be safe, the foreign key is created after the
    # table is created.
    add_foreign_key(:videos, :videos, column: :next_video_id)
  end
end
0 голосов
/ 12 января 2019

Вам нужно установить ассоциацию следующим образом:

has_one :prev_video, :class_name => 'Video', :foreign_key => 'previous_video'

Установив, что вы можете звонить

@video.prev_video

Внешний ключ - это столбец базы данных, который я назвал prev_video, который можно назвать по вашему желанию, если вы не используете то же имя, которое вы дали столбцу db (previous_video).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...