2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Railsで1対1のモデル関連付けを学習する

Posted at

はじめに

これまで1対1の関連付けをしたことがなかったので
実装して検証してみました。

動機

私の場合は、ユーザーの認証機能にdevise_token_authのGemを用いており
それによって、Usersテーブルに認証に関わるカラムが増えてしまいました。

そこで、以下の通り、責務を分けてDB設計をしました。

  • 認証: Userモデル
  • ユーザー特性: Profileモデル

DB設計において、テーブルを分けるとクエリ数が増えてしまい
パフォーマンスが落ちますが、
一方で、自分の可読性を考慮すると1テーブルに集約させすぎるのも…
と考え、この設計にしました。

作業内容

  • モデル関連付け
  • 検証1: テーブルが正しく作成できているか
  • テストデータ作成
  • 検証2: 関連付けが正しくできているか

前提

devise_token_authで認証機能を実装時にUsersモデルを作成済み

モデル関連付け

Railsガイドを参考に実装していきます。

ターミナル

# generateコマンドでマイグレーションファイルとモデルを生成する
% rails g model profile

root/db/migrate/20220221xxxxxx_create_profiles.rb

class CreateProfiles < ActiveRecord::Migration[6.0]
  def change
    create_table :profiles do |t|
      # 生成するカラムを追加する
      t.belongs_to :user, index: { unique: true }, foreign_key: true
      t.string :gender
      t.string :residence
      t.text :introduction
      --- 他カラム... ----

      t.timestamps
    end
  end
end

root/app/models/profile.rb

class Profile < ApplicationRecord
  # ProfileはUserに従属する
  belongs_to :user
end

root/app/models/user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  include DeviseTokenAuth::Concerns::User

  --- 省略 ---
  # UserはProfileを1つしか持たない
  has_one :profile, dependent: :destroy
  --- 省略 ---

end
ターミナル

# マイグレーションを実行してDBに反映させる
% rails db:migrate

検証1: テーブルが正しく作成できているか

ターミナル

# MySQLにrootユーザーで接続する
% mysql -u root -pパスワード

# 作成済みのデータベースを確認
% show databases;

# 使用するデータベースを選択
% use 対象データベース名;

# 作成済みのテーブルを確認
% show tables;

# Profilesのカラムが正しく設定できているか確認
% desc profiles;

# Profilesテーブルの中身が空である事を確認
% select * from profiles;

# MySQLから抜ける
% exit

テストデータ作成

root/db/seeds.rb

# テストユーザーを作成
User.create(
  name: 'Pokemon Sedai',
  email: 'monster@ball.com',
  password: 'pikachu1234',
  password_confirmation: 'pikachu1234'
)
User.create(
  name: 'Takeshi Iwark',
  email: 'ishi@tubute.com',
  password: 'pass1234',
  password_confirmation: 'pass1234'
)

# 上記ユーザーに紐づくプロフィールを作成
Profile.create(
  user_id: 1,
  gender: 'man',
  residence: 'Osaka',
  introduction: 'はじめまして...',
  --- 他カラム ---
)

ターミナル

# テストデータをDBに流す
% rails db:seed

検証2: 関連付けが正しくできているか

ターミナル

# 検証のためにコンソールに入る
% rails c --sandbox

# userという変数にテストユーザーのオブジェクトを入れる
> user = User.first

# profileという変数にテストユーザーのプロフィールを入れる
### (関連付けによって、Userモデルのオプジェクトにprofileメソッドが使える)
### (テストユーザーのプロフィールはseedで作成済み)
> profile = user.profile

# 格納したプロフィール情報を参照できる
> profile

# テストユーザーで新たにプロフィールを作成してみる
### (関連付けによってcreate_profileメソッドが使える)
> other_profile = user.create_profile(introduction: 'こんにちは...')

 ↓

# しかし、テストユーザーのプロフィールは既に存在するため作成できない
### seedデータで作成しているので、Duplicate(重複)とエラーが出る
ActiveRecord::RecordNotUnique (Mysql2::Error: Duplicate entry '1' for key 'profiles.index_profiles_on_user_id')

# テストユーザー2のオブジェクトを作成
> other_user = User.second

# テストユーザー2は初めてプロフィールを作成するので成功する
### (テストユーザー2はseedでプロフィールを作成していない)
> profile = other_user.create_profile(introduction: 'こんにちは...')

終わりに

まだまだRailsで実装することにも慣れてないなー

ポートフォリオ完成にいつになるのやら…

最後までお読み頂き、ありがとうございました!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?