4
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?

はじめに

この記事は2023年度の振り返りです。

こちらの続きとなります。

問題を解いてる時の実話を元に、作成しております

勉強会内の小話

講師:前回、joinの中で紐づけをしてたけど、直接呼べるようにリレーションを組んでおけば楽なので、今回はそれをやってみよう!

初学者達:わかりました!has_manyのthroughですよね!参考書で勉強してる時に読みました!

講師:知ってるなら話は早い。やってみよう!

初学者達:はい!

初学者達:こんな感じでどうでしょう!

class Comic < ApplicationRecord
  has_many :writes, foreign_key: 'book_id'
  has_many :author, through: :writes
end
p Comic.joins(:author).where(author: { name: '冨樫 義博' })

講師:発行されるクエリを確認してみよう

SELECT `comics`.* 
FROM `comics` 
INNER JOIN `writes` ON `writes`.`book_id` = `comics`.`id` 
INNER JOIN `authors` `author` ON `author`.`id` = `writes`.`user_id` 
WHERE `author`.`name` = '冨樫 義博'

講師:うん。前回と同じになって、rubyのソースは少し短くできたね。ここの問題としては終了だけど、せっかくhas_manyを触ってるから深堀をしてみよう。

講師:今リレーションの名前をモデルもしくはテーブル名を割り当ててるけど、それを変えてみよう

初学者達:ん?こんな感じですか?

class Comic < ApplicationRecord
  has_many :kaku, foreign_key: 'book_id'
end

初学者達:これ絶対つながらないので、どのクラスにつなぐかオプションが必要ですよね。。。

初学者達:これでどうでしょう?

class Comic < ApplicationRecord
  has_many :kaku, foreign_key: 'book_id', class_name: 'Write'
end

講師:確認してみよう

comic = Comic.all.first
comic.kaku
SELECT `writes`.* FROM `writes` WHERE `writes`.`book_id` = 1

講師:OK。あってるね。これも前回同様にリレーション名に関連モデル名を指定したことで紐づけするクラス名をrailsが解釈をしててくれてたわけだ。

初学者達:なるほど・・・

講師:じゃぁ、同じ要領で他のも修正してみよう

初学者達:はい!

初学者達:せんせー。ここまで書いたんですが、詰まりました!

class Comic < ApplicationRecord
  has_many :kaku, foreign_key: 'book_id', class_name: 'Write'
  has_many :kaita_hito, through: :kaku
end
class Write < ApplicationRecord
  belongs_to :hito, foreign_key: 'user_id', class_name: 'Author'
  belongs_to :manga, foreign_key: 'book_id', class_name: 'Comic'
end
class Author < ApplicationRecord
  has_many :kaita, foreign_key: 'user_id', class_name: 'Write'
end
comic = Comic.all.first
comic.kaita_hito
/usr/local/bundle/gems/activerecord-7.1.2/lib/active_record/reflection.rb:1092:in `check_validity!': Could not find the source association(s) "kaitahito" or :kaitahito in model Write. Try 'has_many :kaitahito, :through => :kaku, :source => <name>'. Is it one of hito or manga? (ActiveRecord::HasManyThroughSourceAssociationNotFoundError)

講師:エラーに全てヒントが出てるじゃん。。。

初学者達:sourceを使えっていうのは分かったんですが、なんで「hito or manga」なのかがイマイチ。。。

講師:なるほど。フローで考えると、こんな感じかな
image.png

初学者達:なるほど!。sourceって、リレーション先でのリレーション名を指定するのですね!

初学者達:ん?ってことは、前回のも?

講師:そう。前回のcomicモデルにauthorのリレーションを組んだ際も、railsがsourceはauthorと解釈して、こんな感じにリレーションを組んでくれてたんだ。
image.png

初学者達:へーーー。すごいですね

講師:そうだな。ただ、今回はリレーション名を関連モデル名とは異なる名称にしてるので、自分で指定してやる必要がある

初学者達:納得しました!これでどうでしょう!?

class Comic < ApplicationRecord
  has_many :kaku, foreign_key: 'book_id', class_name: 'Write'
  has_many :kaita_hito, through: :kaku, source: :hito
end
class Write < ApplicationRecord
  belongs_to :hito, foreign_key: 'user_id', class_name: 'Author'
  belongs_to :manga, foreign_key: 'book_id', class_name: 'Comic'
end
class Author < ApplicationRecord
  has_many :kaita, foreign_key: 'user_id', class_name: 'Write'
end

講師:確認してみよう

comic = Comic.all.first
comic.kaita_hito
SELECT `authors`.* 
FROM `authors` 
INNER JOIN `writes` ON `authors`.`id` = `writes`.`user_id` 
WHERE `writes`.`book_id` = 1
=> 
[#<Author:0x00007f18600fad50
  id: 1,
  name: "岸本 斉史",
  created_at: Sat, 23 Dec 2023 02:56:25.453889000 UTC +00:00,
  updated_at: Sat, 23 Dec 2023 02:56:25.453889000 UTC +00:00>]

講師:うんいい感じですね。

初学者達:やったー!

講師:次回は、さらに発展型をしてみよう

次回へ続く(次回が最終回です)

さいごに

ここはよく甘い認識のまま利用してました!っていう声が多かったので、常々記事にしたいと思っていました。
この部分を説明したいがゆえに、長い説明を入れていたといっても過言ではありません。(前部分が理解できていないと関係上、説明しづらいのです。)
ここまで連続で読まれた方、読みにくい文章をご拝読頂きましてありがとうございました。次回が最終回となります。最後まで読んで頂けますと嬉しい限りです。

4
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
4
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?