` Histice one 'とのトラブル


最近、私は論文に取り組んでいて、柵の中でハッサク一つの協会を使用することについておもしろい問題に遭遇しました.しかし、我々がそれに入る前に、関連がどのようにレールで働くかについて少し理解するために、一歩後退しましょう.

レール協会


私は、これを読んでいる皆がデータベースとオブジェクトリレーショナル・マッパについて深く知っているか、理解するつもりでないと仮定します.もっと深く理解したいならRails docs この特定の文脈でこれを理解する良い出発点です.
別のクリエイターが投稿を作成することができるコンテンツサイトを構築するには、次のような2つのテーブル作成者とポストを持つリレーショナルデータベースを持っています.

あなたのCreatorテーブルは、作成されるすべてのアイテムに対してidとname列を持ち、投稿テーブルはすべての項目に対してid、title、type、body columnを持ちます.各列において、主キーは各レコードの一意の識別子であるため、ID列になります.The primary key として機能するので、関連付けを作成するときに重要ですforeign key 関連付けられたテーブルで.
ここで、どのテーブルがどの投稿を作成したのか知りたいので、2つのテーブルがどのような関係を持つかを決める必要があります.あなたが作ることができるいくつかの異なる種類の協会があります、しかし、私は2つに触れるだけです.

多くの


多くの関連付けは、テーブル内の1つの項目を別のテーブルの多くの項目と関連付けることができます.例えば、私たちのシステムが標準的なコンテンツ作成システムであるなら、作成者は多くのポストを持つことができます.
class Creator < ApplicationRecord
  has_many :posts
end
class Post < ApplicationRecord
  belongs_to :creator
end
データベースは次のようになります.

The creator_id は、id CREATETABLEテーブルの主キーであり、POSTテーブルの外部キーとして動作します.それで、あなたがティファニーPollardによって作成されるすべてのポストを見つけたかったならば、あなたはcreator_id マッチティファニーポラードのid 作成者テーブルで.

ハシネスワン


エーhas_one 関係は、テーブルの1つの項目が別のテーブル(1つ以上)の1つのアイテムと関連付けられることができるだけであると言います.私たちは、作成者が1つのポストだけを作成することができるシステムを作成したいかもしれません.
class Creator < ApplicationRecord
  has_one :post
end
class Post < ApplicationRecord
  belongs_to :creator
end
創作者has_one ポストとポストbelongs_to 創造主.データベースは以前と同じです.

と同じようにhas_many the creator_id クリエイターのための外部キーですid ポストテーブルで.
さて、今問題に.
...

問題


あなたが作成するレールでhas_one アソシエーション、明らかに仮定は、創造主が1つのポストだけを持つことができるということです.それで、作者が別のポストを作成しようとするとき、何が起こりますか?あなたは、ポストが存在するかどうかを確認するのをチェックしてください、そして、彼らがポストを取り替えるか、ちょうどそれが創造者の意図であると仮定とポストを交換するならば、創造主に尋ねてください.しかし、それは何が起こるかではなく、代わりに、このエラーを得る

これは一般的なエラーですhas_one そして、これできれいに要約されますissue :

This is because prior to deleting, the foreign key of the target association is set to nil and a save operation is performed on the target.


これがなぜ起こるのかはっきりしていません.あなたがこの問題を解決するならば、2014年に作成され、議論はまだ進行中です.これはバグとして始まったようですが、望ましい機能になるように進化しているかもしれません.

フィックス



これを修正する方法はいくつかあります.基本的には、新しい関連付けを行う前に古いアソシエーションが削除されることを確認します.したがって、あなたのモデルでこれを行うことができます.
class Creator < ApplicationRecord
  has_one :post, dependent: :destroy
end
class Post < ApplicationRecord
  belongs_to :creator
end
または、リソースを作成する方法(コントローラや特定のlibファイルのいずれか)では、次のように実行できます.
creator = Creator.find_by_id(id)
creator.post&.delete
任意のポストを作成する前に.カバレッジブックからアンディクロル推奨rolling things up in a transaction そして、より多くの提案がありますGitHub issue も.

更なる読書

  • Be Careful Assigning has_one Relations
  • Building a has_one association fails on save if target has a validation on foreign_key
  • BBC Bitesize: Introducing Databases
  • Rails ActiveRecord Associations