Rails 6 migration add foreign key association between existing tables

Viewed 1127

I have two tables talks and media.

  1. The talks may have 0 or 1 media.
  2. The media can have other rows that is not associated to any talks.

I'm planning to add a foreign key to the talks table to a field media_id (that references media), so that if media is deleted, media_id would be null. Though not super necessary, it'd be great to have the associated media to be deleted when talks row is deleted, if any.

The current migration looks like, it runs fine and generates the media_id on the talks table as I want:

class AddMediaToTalks < ActiveRecord::Migration[6.0]
  def change
    add_reference :talks, :media, type: :integer, foreign_key: true
  end
end

But, I'm not so sure about what I need to put on the models, I mean has_one and belongs_to. I am not sure which would go to which model, or even if I need only one or neither or both.

I also tried adding on_delete: :nullify to the migration script, but it doesn't really have any effect. I'm using mysql, btw. When I try to delete associated media, it fails because it is referenced in the talks table.

Disclaimer : I am fairly new to Rails. Thanks.

1 Answers

Since you put the foreign key into talks that means talks belongs to media (because it can only belong to one media (the media_id column in talks can only hold one value/one id).

In the Rails guide you find some more information on how to choose between belongs_to and has_one, the main indicator is in which table you place the foreign key. https://guides.rubyonrails.org/association_basics.html#choosing-between-belongs-to-and-has-one (Depending on your use case you might want to say a talk has a medium(?) and change it around again - but that would mean to change the migration too!).

If you want to delete the media when the talk is deleted just add dependent: :destroy to the talk model:

class Talk
  belongs_to :media, dependent: :destroy
end

And for this problem:

When I try to delete associated media, it fails because it is referenced in the calls table.

That means you're missing the dependent: :destroy in the calls model, (if deleting all associated media when deleting a call is if what you want). Alternatively, you could also delete media first and then calls.

Related