37日目 データベースのテーブル同士の関連付け対応③(Railsにおけるアソシエーションの定義)

おはようございます。昨日の記事の続きです。

わたしの頭の中には、以下のER図のように、初期のデータベースとして、「Room」「User」「Comment」という3つのモデルがあって、その3つのモデルからチャットができるようなアプリを構想しております。

ER図

それで、昨日までで、JRuby on Railsを用いて3つのモデルを作成し、そのモデルをデータベースへと反映しました。
そして、今度はそれらのモデル同士の関連付け(アソシエーション)を行ないます。

Railsのアソシエーションとは?

アソシエーションとは、Railsにおいてモデル同士の関係性を構築するための仕組みのことであり、アソシエーションを行なうことによって、あるモデルに対応する他のモデルを扱うことを容易にしてくれます。

例えば、先ほどのER図のように、「User」と「Comment」というモデル(≒データベースのテーブル)があって、「Comment」は「User」の「ID」という列(主キー)を設定できる「ユーザーID」という列(外部キー)があるとします。(以下にも図を載せます。)

画像

アソシエーションを定義しない場合、Rails上で「IDが1のUser(ユーザー)」による「Comment(コメント)」を取得するソースコードを書こうと思ったら、以下のような書き方になります。

# アソシエーションを定義しない場合
user = User.find(1) # User(ユーザー)のIDが1であるレコード(オブジェクト)を取得
comments = Comment.where(user_id: user.id) # IDが1のuserが発したComments(コメント)を取得

たくさんある「Comment(コメント)」の中から、「ユーザーID」という外部キーを使って、IDが1のものを見つけてくる感じになります。

ここで、アソシエーションを定義した場合、ソースコードの書き方は以下のようにシンプルなものに変わります。

# アソシエーションを定義した場合
user = User.find(1) # User(ユーザー)のIDが1であるレコード(オブジェクト)を取得
comments = user.comments # IDが1のuserが発したComments(コメント)を取得

前者の場合は「comments = Comment.where(user_id: user.id)」というように、comment(コメント)を取得する際には「外部キーに特定のユーザーIDを指定してコメントを検索する」というような書き方になりますが、

後者の場合は「comments = user.comments」となり、comment(コメント)を取得する際には「特定のユーザーのコメントを参照する」というようにシンプルな書き方に変わります。

このようにアソシエーションを定義しておくと、Railsにおいてモデルをシンプルに扱うことができるようになり、プログラミングを容易にすることができます。

アソシエーションの定義

では、実際にアソシエーションの定義を行なってみます。今回、モデル同士の関係性を構築したいものは、以下の①と②です。
①「Room」と「User」は1対1以上の関係がある
②「User」と「Comment」の1対0以上の関係がある

そこで、Visual Studio Codeを起動して、Railsアプリケーションのプロジェクトデータがある場所を開いてみます。そしたら、Visual Studio Codeの画面左側に「エクスプローラー」ビューが表示されていると思うので、そこから「app」⇒「models」の順にクリックしてファイル等を展開してみます。

そしたら、以下のように「comment.rb」など、「Comment」「Room」「User」モデルと対応するmodelファイルがあると思います。

※上記のmodelファイルは、以下の32日目の記事を書いた時に作成されたものです。

では、まず「Room」モデルに対応する「room.rb」から編集します。「room.rb」をクリックして開くと、以下のようなコードの内容になっているかと思います。

class Room < ActiveRecord::Base
end

ここで、「room.rb」に対して行うことは、抽象的に述べるならば、
【①「Room」と「User」は1対1以上の関係がある】
という関係性を構築するために、
・「Room」に対応する「User」が「1以上(複数)」ある
というアソシエーション(関連付け)を定義することです。

具体的には、先ほどのコードから以下のコードへと内容を変更します。

class Room < ActiveRecord::Base
    has_many :users # 対応する「User」が「複数」
end

「has_many :users」というものが追加されていますが、これは
『「Room」に対応する「User」は「複数」あり、そして、その複数の「User」は【users】という名前で参照することができる』
という意味になります。

ただ単に「1以上(複数)」あると関連付けるだけでなく、【users】という名前で参照できるように定義することによって、「Room」から複数の「User」モデルをシンプルに扱うプログラミングが可能になります。

続けて、「User」モデルに対応する「user.rb」も編集します。「user.rb」をクリックして開くと、先ほどの変更前の「room.rb」と同様に以下のようなコードになっているかと思います。

class User < ActiveRecord::Base
end

「user.rb」を編集する場合は、
【①「Room」と「User」は1対1以上の関係がある】
【②「User」と「Comment」の1対0以上の関係がある】
という2通りの関係性を構築しておきたいので、

「User」は「1つ」の「Room」に追随する
・「User」に対応する「Comment」が「0以上(複数)」ある
という2つのアソシエーション(関連付け)を定義します。

具体的には、以下のコードへと内容を変更します。

class User < ActiveRecord::Base
    belongs_to :room # 「1つ」の「Room」に追随する 
    has_many :comments # 対応する「Comment」が「複数」
end

追加したのは2行あり、まず1つめの「belongs_to :room」ですが、
『「User」は「1つ」の「Room」に追随し、そして、その「Room」は【room】という名前で参照することができる』
という意味になります。

また、2つめの「has_many :comments」については、
『「User」に対応する「Comment」は『複数』あり、そして、その複数の「Comment」は【comments】という名前で参照することができる』
という意味になります。

最後に、「Comment」モデルに対応する「comment.rb」も編集を行ないます。「comment.rb」をクリックして開くと、以下のようなコードになっているかと思います。

class Comment < ActiveRecord::Base
end

「comment.rb」では
【②「User」と「Comment」の1対0以上の関係がある】
という関係性を構築したいので、
「Comment」は「1つ」の「User」に追随する
というアソシエーション(関連付け)を定義します。

具体的には、以下のコードへと内容を変更します。

class Comment < ActiveRecord::Base
    belongs_to :user # 「1つ」の「User」に追随する  
end

ここで、「belongs_to :user」という行が追加されていますが、これは
『「Comment」は「1つ」の「User」に追随し、そして、その「User」は【user】という名前で参照することができる』
という意味になります。

これですべてのアソシエーションの定義が終わったことになります。

定義したアソシエーションを図示すると

前章でアソシエーションした結果、どうなるのか図示すると以下のように、モデル同士で参照ができるようになります。

参考

アソシエーションについては以下の記事に詳しく載っていますので、お時間・ご興味がありましたらご覧ください。

おわりに

ここまで読んでくださってありがとうございました。
データベースのテーブル同士の関連付け対応は③にて一旦おわります。次回からはそろそろアプリケーションの見た目(View)の部分をいじろうと思います。

次回もよろしくお願いいたします。

この記事が気に入ったらサポートをしてみませんか?