はじめに
railsしっかり勉強し始めて、半年くらいたちます。(多分)
最近学んだこと多いので、アウトプットしていきますー。
ちょっと説明下手だったり、間違ってたりする部分あるかもしれないので、ご了承ください!!
has_oneとhas_manyって?
両方とも、モデルの関係定義に使われるものです。
has_one
とは、1つのモデル(親)に対して、1つのモデル(子)を持つこと(1対1の関係を持つ)ができるということを定義する場合に使います。
例:)1つの投稿に対して、画像を1枚添付することができる。
has_many
とは1つのモデル(親)に対して、たくさんの同じモデル(子)を持つこと(1対多の関係を持つ)ができることを定義する場合に使います。
例:)1つの投稿に対して、画像を複数枚添付することができる。
違いについて
has_one
やhas_many
で関連づけられたモデルを親と関連づけて作成したい場合、それぞれ作成方法が異なるので、気をつけましょう!
実際のコードを見てみる
class Image < ApplicationRecord
mount_uploader :image, ImageUploader
belongs_to :tweet_image, foreign_key: :tweet_id, optional: true #optional: trueをつけることによって、外部キーがなくても、保存できる
end
class TweetImage < Tweet
validates :content, presence: true, length: { maximum: 140 }
belongs_to :user
has_one :image, foreign_key: :tweet_id
accepts_nested_attributes_for :image, allow_destroy: true
end
ここのコードだと、accepts_nested_attributes_for :image
を使って、TweetImage
を保存する時、同時に子モデルのImage
を保存するので、Image
モデルのファイルにoptional: true
をつけて、外部キーが存在しなくても保存できるようにしておくことが必要です。
class TweetsController < ApplicationController
before_action :authenticate_user!
def new
@tweet = TweetImage.new
@tweet.build_image #has_oneの関係の場合
end
class TweetsController < ApplicationController
before_action :authenticate_user!
def new
@tweet = TweetImage.new
@tweet.images.build #has_manyの関係の場合
end
上記は私が、制作物を作った際につかっているコードです。
関係性を図で表すとこんな感じです。
TweetとTweetImageはSTIを使った継承関係で、
TweetImageはhas_one
で画像(Imageモデル)を持っています。
コントローラはTweetのコントローラのみで管理しているので、画像を添付する場合のために必ずはじめはTweetImageである必要がありました。(accepts_nested_attributes_forを利用しているため、Formの部分に画像添付の部分を出せなくなってしまうため。)
newでモデルを作ることもできますが、IDを1回ごとに渡さないといけないので、少し面倒です。build
を使うと、自動でIDを入れてくれるので、簡潔にコードを書くことができます。
最後に
説明が物足りてないところがありますが、ここで終わります!
ここ違うよってとこありましたら、コメントでご指摘お願いします!!