J'ai ce modèle:RoR: intégrité référentielle niveau base de données
class Book < ApplicationRecord
has_many :pages, dependent: :destroy
end
Et celui-ci:
class Page < ApplicationRecord
belongs_to :book
end
La migration pour le Book
est:
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :books do |t|
end
end
end
Et la migration pour Page
est:
class CreatePages < ActiveRecord::Migration[5.0]
def change
create_table :pages do |t|
t.references :book, index: true, null: false
end
end
add_foreign_key :pages, :books, on_delete: :cascade
end
De plus j'ai eu quelques graines:
Book.create!(
pages: [
Page.new,
Page.new,
Page.new
]
)
rake db:migrate
, rake db:seed
et tout ce jazz. Je saute dans les rails c:
Book.first
Book Load (0.1ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Book id: 1>
Cool .... maintenant?
Page.count
(0.3ms) SELECT COUNT(*) FROM "pages"
=> 3
Donne un sens total. Suivant:
Book.first.destroy
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.1ms) begin transaction
Page Load (0.1ms) SELECT "pages".* FROM "pages" WHERE "pages"."book_id" = ? [["book_id", 1]]
SQL (0.1ms) DELETE FROM "pages" WHERE "pages"."id" = ? [["id", 1]]
SQL (0.0ms) DELETE FROM "pages" WHERE "pages"."id" = ? [["id", 2]]
SQL (0.0ms) DELETE FROM "pages" WHERE "pages"."id" = ? [["id", 3]]
SQL (0.1ms) DELETE FROM "books" WHERE "books"."id" = ? [["id", 1]]
Yay! Presque là ... après ensemencement à nouveau je fais ceci:
Book.first.delete
Book Load (0.1ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
SQL (144.0ms) DELETE FROM "books" WHERE "books"."id" = ? [["id", 2]]
WTF?
Page.count
(0.1ms) SELECT COUNT(*) FROM "pages"
=> 3
Je sais delete
ne déclenche pas callbacks, de sorte que dependent: :destroy
ne me aidera pas ici. Mais la clé étrangère? Bonjour? Je veux l'intégrité référentielle dans mon niveau de base de données !! Qu'est-ce que je fais mal? J'ai essayé d'autres choses, comme le déplacement de la on_delete: :cascade
à la définition du champ:
def change
create_table :pages do |t|
t.references :book, index: true, null: false
end
end
Mais ... Nope, même résultat. J'ai recherché et lu la documentation ActiveRecord deux fois, et quelques autres questions dans SO m'ont indiqué mon installation actuelle (qui n'est pas le projet sur lequel je travaille, mais plutôt un nouveau projet avec la même configuration de base pour répliquer le erreur - oui, elle échoue là aussi), mais je ne peux tout simplement pas mettre le doigt sur ce qui ne va pas. Peut-être que c'est trop tard et que je suis trop fatigué. Aidez-moi? Est-ce que Rails supporte même cela? J'utilise v5, loin, loin devant 4.2 où les contraintes au niveau db ont été intégrées. Mon db/schema.rb
ressemble à ceci:
ActiveRecord::Schema.define(version: 20160218232358) do
create_table "books", force: :cascade do |t|
end
create_table "pages", force: :cascade do |t|
t.integer "book_id", null: false
t.index ["book_id"], name: "index_pages_on_book_id"
end
end
Aucune trace de clés étrangères?
Y a-t-il une raison pour laquelle vous utilisez delete au lieu de détruire? Si quelque chose, vous pouvez toujours utiliser Dépendance:: delete_all, qui est essentiellement un nuke de l'orbite. Il ne se souciera de rien concernant les pages et leurs dépendances. – David
Aucune raison particulière en plus d'apprendre et de me sauver des ennuis futurs - Rails réclame l'intégrité référentielle au niveau db est faisable, et j'aimerais l'obtenir. –
https://robots.thoughtbot.com/referential-integrity-with-foreign-keys pourrait vous aider. – David