はじめに
Q&Aアプリを作成しています。DB設計で改修が必要になったので記事にしました。
今回はモデルの関連付けを解消します。
改修前のDB設計
【解答】
質問(Question)に対して、最初に投稿(アソシエーション)されたCommentのオブジェクト
【コメント】
解答に対して、投稿(アソシエーション)されたCommentのオブジェクト
ややこしい!
改修後のDB設計(予定)
解答をAnswerテーブル、コメントをCommentテーブルに分けます。
こちらの方が管理しやすいコードだと思います。特定の質問の解答やコメントを取得するのも簡単です。
Answerテーブルで解答機能を実装できるまで、UserテーブルとQuestionテーブルはCommentテーブルの関連付けを解消します。
関連付けを解消する前に
開発環境のDBにCommentのオブジェクトがあるのでリセットします。
rails db:migrate:reset
Commentのサンプルデータは不要なので削除します。(この記事ではコメントアウト)
# other = User.last
# questions = User.first.questions.order(:created_at).take(6)
# 5.times do
# user_id = other.id
# content = Faker::Lorem.sentence(word_count: 3)
# questions.each { |question| question.comments.create!(user_id: other.id,
# content: content) }
# end
データを投入します。Commentのデータが生成されていないことを確認できました。
rails db:seed
関連付けの解消
has_many
あるUserとCommentはhas_many(1対多)の関係性
あるQuestionとCommentはhas_many(1対多)の関係性
has_manyをコメントアウトにします。
class User < ApplicationRecord
has_many :questions, dependent: :destroy
# has_many :comments, dependent: :destroy
end
class Question < ApplicationRecord
# has_many :comments, dependent: :destroy
end
belongs_to
あるCommentはUserとbelongs_to(1対1)の関係性
あるCommentはQuestionとbelongs_to(1対1)の関係性
belongs_toをコメントアウトにします。関連付けのバリデーションも不要です。
class Comment < ApplicationRecord
# belongs_to :user
# belongs_to :question
# validates(
# :user_id,
# presence: true
# )
# validates(
# :question_id,
# presence: true
# )
end
テスト
これで関連付けは解消されました。(既存の)テストで確認してみます。
require 'rails_helper'
RSpec.describe Comment, type: :model do
let(:other) { FactoryBot.create(:user) }
let(:question) { FactoryBot.create(:question) }
let(:comment) { question.comments.build(user_id: other.id,
content: "Example content")}
it "有効であること" do
expect(comment).to be_valid
end
end
テストを実行。ちゃんと失敗しました。関連メソッドが使えないようになりました。
無事、関連付けが解消できました!!!
NoMethodError:
undefined method `comments' for #<Question id: 3131, ~~~~
あとがき
DB設計は本当に大切だと認識させられました!アプリ開発がまだ序盤の方で助かりました
あと、テストはできる限り先に書きましょう!テストが無いと、他のDBデータや機能に影響が出てしまっていないか確認するのが困難になります。(先に書いてて良かった.....)
これからルーティング、コントローラ、ビューを改修していきます。これらについても記事にしていく予定です。