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モデルを使う
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に属する」がしっくりとくるので下記のように使い分けると良い
class User < ApplicationRecord
has_one :userimage
end
class Userimage < ApplicationRecord
belongs_to :user
end
@user.userimage.name
→ プロフィール画像のファイル名を参照できる
#③has_many
【1:nの関係を表すことができるアソシエーション】
・has_many関連付けが使用されている場合、「反対側」のモデルではbelongs_toが使用されることが多い。
・従属する側(今回はarticleモデル)のテーブルに、相手のモデル(今回はuserモデル)のidが必要→テーブルにも紐付けをする
「1人のユーザー(Userモデル)に対して、複数の記事(Articleモデル)が存在する」と言う例の場合
class User < ApplicationRecord
has_many :articles # => userはarticleを複数持っていると解釈する
end
※has_many関連付けを宣言する場合、相手のモデル名は「複数形」にする必要がある。
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 |
class Article < ApplicationRecord
has_many :article_tags
has_many :tags, through: :article_tags
end
class Tag < ApplicationRecord
has_many :article_tags
has_many :articles, through: :article_tags
end
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