9
11

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 5 years have passed since last update.

【Rails】モデルの関連付け(アソシエーション)の概要と使い方

Last updated at Posted at 2019-03-16

Progateでモデル同士の紐付け(変数の代入で)を学んだけれども、アソシエーションの機能でもっと簡単に出来ると聞いたので調べてまとめてみた。

#アソシエーションとは
【アソシエーション = モデル間の関連付け】

更に言うと、2つのActive Recordモデル同士のつながりを指す。
(Railsの自作したモデルはApplicationRecordモデルを継承し、さらにApplicationRecordモデルはActiveRecord::Baseを継承している)

アソシエーションを利用すると、複数のテーブルにまたがるデータの操作をより簡潔に行うことが出来る。

#テーブル(モデル)間の関係性について

テーブル(モデル)間の関係性については以下3通りが存在する

① 1:1
(例)1人のユーザーに対して、プロフィール写真は1枚存在する

②  1:n (1:多)
(例)1人のユーザーに対して、複数の記事が存在する

③  n:m  (多:多)
(例)記事とタグの関係
→・ある記事はRailsだったりRubyだったり・・・複数のタグをもつ。
 ・あるタグ(Railsタグとする)は、様々な記事についている。

#今回例として用いるモデル
※本来であればモデルにしなくても良いものも含んでいるが便宜上として考えてほしいです

・Userモデル
・Userimageモデル → Userのプロフィール写真について定義するモデル
・Articleモデル
・Tagモデル
・Article_Tagモデル

users userimages articles tags article_tags
id id id id id
name name name name article_id
user_id tag_id

※主キーと外部キーに関して
・主キー :関係データベースにおける行(レコード)を一意に識別するための列(カラム)(usersテーブルやarticlesテーブル等のid)
・外部キー:他のテーブルとの関連づけに使うキー(articleテーブルのuser_id、article_tagsテーブルのarticle_idやtag_id)

#関連付けの種類
Railsには下記6種類の関連付けが存在するが、今回は①〜④について詳細にみていく
①belongs_to
②has_one
③has_many
④has_many :through
⑤has_one :through
⑥has_and_belongs_to_many

#①belongs_to
【参照元テーブルから参照先テーブルの情報にアクセスする】 (1:1の関係性)
例としてUserモデルとUserimageモデルを使う

userimage.rb
 class Userimage < ApplicationRecord
  belongs_to :user
 end

上記のように書くと、参照先(Userモデル)の情報をUserimageのインスタンスで利用できるようになる。
@userimage.user.name→ ユーザーの名前を参照できる

※belongs_to関連付けで指定するモデル名は必ず「単数形」にしなければならない

#②has_one
【1:1の関係を表すことができるアソシエーション】

関係性のみで言えば「belongs_to」と同じだが、has_oneとの使いわけに関しては下記の通り

has_one関連付けの場合は、その宣言が行われているモデルのインスタンスが、他方のモデルのインスタンスを「まるごと含んでいる」または「所有している」ことを示します。

つまり、UserとUserimage(プロフィール画像)の関係性で言うと
「UserimageはUserに属する」がしっくりとくるので下記のように使い分けると良い

user.rb
 class User < ApplicationRecord
   has_one :userimage
 end
userimage.rb
  class Userimage < ApplicationRecord
   belongs_to :user
  end

@user.userimage.name→ プロフィール画像のファイル名を参照できる

#③has_many
【1:nの関係を表すことができるアソシエーション】
・has_many関連付けが使用されている場合、「反対側」のモデルではbelongs_toが使用されることが多い。
・従属する側(今回はarticleモデル)のテーブルに、相手のモデル(今回はuserモデル)のidが必要→テーブルにも紐付けをする

「1人のユーザー(Userモデル)に対して、複数の記事(Articleモデル)が存在する」と言う例の場合

user.rb
 class User < ApplicationRecord
  has_many :articles # => userはarticleを複数持っていると解釈する
 end

※has_many関連付けを宣言する場合、相手のモデル名は「複数形」にする必要がある。

article.rb
 class Article < ApplicationRecord
  belongs_to :user # => articleはuserに従属すると解釈する
 end

上記2点を書けば・・・記事名を表示できる

コントローラ側
@user = User.find_by(id:1)
ビュー側
<% @user.articles.each do |article| %>
  <%= article.name %>
<% end %>

※belongs_toと違い、articlesメソッドの戻り値が配列になることに注意

#④has_many :through
【m:nの関係を表すアソシエーション】
前半で例としたように、「記事とタグの関係」を例としてみていく
今回登場するモデルは下記の通り

articles article_tags tags
id id id
name article_id name
user_id(今回関係なし) tag_id
article.rb
 class Article < ApplicationRecord
  has_many :article_tags
  has_many :tags, through: :article_tags
 end
tag.rb
 class Tag < ApplicationRecord
  has_many :article_tags
  has_many :articles, through: :article_tags
 end
article_tag.rb
 class ArticleTag < ApplicationRecord
  belongs_to :article
  belongs_to :tag 
 end

タグ名を取り出したい場合は・・・

コントローラ側
@article = Article.find(1) # id:1の記事情報
ビュー側
#情報を取り出す際は繰り返し処理!
<% @article.tags.each do |tag| %>
  <li><%= tag.name %></li>
<% end %>

※ちなみにArticle_tagテーブルに値をrails consoleで入れる際は
ArticleTag.new(article_id: "1", tag_id: "1")
とモデル名の通り入れる(Article_tag.newだといつまでたっても値入れられない!←ハマりました・・・)

このようにアソシエーションを使うことで、一つ一つのモデルを順を追って操作していたものが、簡単・簡潔になる。

#参照
Ruby on Railsガイド : https://railsguides.jp/association_basics.html
【Rails初心者向け】モデル間の関連付け(アソシエーション)まとめ: https://qiita.com/To_BB/items/47d2c7b1bc3513025d7b
Rails モデルの関連付け(アソシエーション):https://qiita.com/taigamikami/items/d6a2b5e4611eb4d8e13a

9
11
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
9
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?