実装したいこと
articleとtagが多対多の関係で、中間テーブルにarticle_tagを設定。タグ名で検索して、そのタグ名に該当する記事を表示させる機能を作ります。
今回は、この機能を実装する上で、自分が間違えたところをアウトプットします。 article.rb
class Article < ApplicationRecord belongs_to :category belongs_to :author has_many :article_tags has_many :tags, through: :article_tags has_many :article_blocks, -> { order(:level) }, inverse_of: :article ... end
article_tag.rb
class ArticleTag < ApplicationRecord belongs_to :article belongs_to :tag end
tag.rb
class Tag < Taxonomy has_many :article_tags has_many :articles, through: :article_tags end
scopeを使って実装
article.rb
scope :by_tag, ->(tag_id) { joins(:tags).where(article_tags: { tag_id: tag_id }) }
class SearchArticlesForm include ActiveModel::Model include ActiveModel::Attributes attribute :tag_id, :integer def search # データベースから重複のないデータを取得してくる relation = Article.distinct # タグで検索内容を絞り込む relation = relation.by_tag(tag_id) if tag_id.present? end end
自分が間違えた内容
article.rb
scope :by_tag, ->(tag_id) { joins(:tags).where( tag_id: tag_id ) }
articleと紐付いているtagsのテーブルをjoinで結合させて、tag_idを取得すればできるのでは?と思っていました。しかしこれをしてしまうと、SQLがテーブルを取得できないエラーが出てしまう。
article = Article.first [26] pry(main)> article => #<Article:0x00007fee1cf737c8 id: 2, category_id: 4, author_id: 3, uuid: "09030ca8-9f8a-44b7-8cd9-2a1b8a696918", slug: "konan", title: "名探偵コナン", description: "真実はいつも一つ", body: "<p>名探偵コナン</p>", state: "draft", published_at: Fri, 25 Jun 2021 18:00:00 JST +09:00, created_at: Sat, 05 Jun 2021 07:01:24 JST +09:00, updated_at: Thu, 10 Jun 2021 18:46:59 JST +09:00, deleted_at: nil>
tag = Tag.first [27] pry(main)> tag Tag Load (1.9ms) SELECT "taxonomies".* FROM "taxonomies" WHERE "taxonomies"."type" IN ('Tag') ORDER BY "taxonomies"."id" ASC LIMIT ? [["LIMIT", 1]] => #<Tag:0x00007fee1578f158 id: 1, type: "Tag", name: "saa", slug: "saae", description: nil, created_at: Thu, 03 Jun 2021 21:20:32 JST +09:00, updated_at: Thu, 03 Jun 2021 21:20:32 JST +09:00> [28] pry(main)>
tagはarticleのカラムならこの記載でいけるが、articleとtagが紐付いているのでテーブルをjoinで結合したらそりゃエラー出ますね。
[33] pry(main)> article.article_tags => [#<ArticleTag:0x00007fee1f096d60 id: 1, article_id: 2, tag_id: 1, created_at: Sat, 05 Jun 2021 07:17:03 JST +09:00, updated_at: Sat, 05 Jun 2021 07:17:03 JST +09:00>, #<ArticleTag:0x00007fee1f0b4ae0 id: 2, article_id: 2, tag_id: 5, created_at: Sat, 05 Jun 2021 07:17:51 JST +09:00, updated_at: Sat, 05 Jun 2021 07:17:51 JST +09:00>]
whereメソッドは「結合先のテーブル名」を指定している事に注意してください。
where(article_tags: {tag_id: tag_id})は、article_tagsテーブルのtag_idカラムに対しての条件になっている。
joinsメソッドの基本的な使い方は、joinsメソッドを実行したArticleモデルのレコードを取得するもので、あくまでも関連するモデルはwhereメソッドなどで条件を指定して絞り込みをしているだけなので注意してください。
参考URL