Reputation: 1303
I am new to ROR, and now doing a course project related to books. I have a "book" table with string 'isbn' as its primary key, and now trying to add another "comment" with reference to the book table with a foreign key 'isbn' to refer to the "book" table . So my "models/comment.rb" looks like this:
class Comment < ApplicationRecord
belongs_to :book, references: :isbn, type: :string
end
And "models/book.rb" is:
class Book < ApplicationRecord
has_many :comments, dependent: :destroy
end
My "books" table looks like: I would expect that the "comments" table generated will contain a column "isbn" (string) after db migration, but in fact the "comments" table generated contained a "book_id" (integer) instead. How can I generate a foreign key to reference to the string primary key "isbn" in "book" table?
Upvotes: 0
Views: 1293
Reputation: 101851
Start by setting up the foreign key column to be the right type and set the foreign key constraint to point to the right column:
class CreateComments < ActiveRecord::Migration[6.0]
def change
create_table :comments do |t|
t.string :title
t.string :note
t.references :book, type: :string, column_name: :isbn
t.timestamps
end
end
end
I would expect that the "comments" table generated will contain a column "isbn" (string) after db migration, but in fact the "comments" table generated contained a "book_id" (integer) instead.
Migrations are actually a lot simpler and dumber than you would think. Its just a DSL that creates SQL statements. Its not actually in any way aware of the other table so it has no way of knowing that books.isbn
is a string column. It just uses the default type for add_reference
which is :integer
. Rails is driven by convention - not artificial intelligence.
If you want to call the column something else like book_isbn
you have to do it in two steps instead:
class CreateComments < ActiveRecord::Migration[6.0]
def change
create_table :comments do |t|
t.string :title
t.string :note
t.string :book_isbn
t.timestamps
end
add_foreign_key :comments, :books,
column: "book_isbn", primary_key: "isbn"
end
end
Then setup the books model to use your non-conventional primary key:
class Book < ApplicationRecord
self.primary_key = :isbn
has_many :comments,
foreign_key: :book_isbn # default is book_id
end
On the comment side you need to configure the belongs_to
association so that it points to books.isbn
instead of books.id
.
class Comment < ApplicationRecord
belongs_to :book, primary_key: :isbn
end
references
is not a valid option for belongs_to
.
ArgumentError (Unknown key: :references. Valid keys are: :class_name, :anonymous_class, :foreign_key, :validate, :autosave, :foreign_type, :dependent, :primary_key, :inverse_of, :required, :polymorphic, :touch, :counter_cache, :optional, :default)
Upvotes: 3