Ruby
Rails

【Rails】タグ付け機能を一対多で実現する方法

はじめに

ツイートにタグ付け機能を付与する際、多対多、一対多のどちらで実装するかでそれぞれのメリットが存在するかと思います。
・多対多のメリット:タグ一覧ページ、タグの詳細ページを実装しやすい。
・一対多のメリット:create,updateが実装しやすい。中間テーブルを作る必要が無い。

今回は一対多での実装の際にネックとなる、tags_controllerにおけるindex action, show actionの作成について投稿させていただきます。
多くの参考記事で多対多による実装が載っていますが、この点さえクリアできれば、一対多の方が簡単に実装できると感じています。)

コード

db/migrate/xxxxx_create_tags.rb
class CreateTags < ActiveRecord::Migration
  def change
    create_table :tags do |t|
      t.string :name, index: true
      t.references :tweet, foreign_key: true
    end
  end
end
app/models/tweet.rb
class Tweet < ActiveRecord::Base
  has_many :tags, dependent: :destroy
end
app/models/tag.rb
class Tag < ActiveRecord::Base
  belongs_to :tweet
end
app/controllers/tags_controller.rb
class TagsController < ApplicationController
  def index
    @tags = []
    Tag.order("name ASC").each do |tag|
      i = 0
      @tags.each do |t|
        if tag.name != t.name
          i += 1
        end
      end
      if i == @tags.length
        @tags << tag
      end
    end
  end

  def show
    @tag = Tag.find(params[:id])
    @tweets = []
    Tweet.all.each do |tweet|
      tweet.tags.each do |tag|
        if tag.name == @tag.name
          @tweets << tweet
          break
        end
      end
    end
  end
end

終わりに

indexのviewページでは、作成されたタグの一覧を表示、showのviewページでは、該当のtagが付けられたツイートの一覧を表示します。
それぞれ、@tags@tweetsを用いることで、タグ,ツイートを被らせることなく表示することを実現できます。
(なお、配列から重複を取り除く際、rubyではuniqというメソッドが存在しますが、配列の中身がハッシュの際に上手く使用できないようなので、今回は上記のようなコードを書きました。また、本記事はgem:acts-as-taggable-onを使用しないことを前提としています。)

以上、内容に不備がございましたら、コメントいただけますと幸いです。