5
3

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

[Ruby on rails] アソシエーションを使ってタグ機能

Posted at

#はじめに
アソシエーションを使ってタグ機能を実装しました。
備忘録的な感じです。良かったら参考にしてみて下さいレベルです。ご了承ください。

用意するもの
簡単なCRUD機能がついたアプリ前提に書いています。

環境
Windows10
Ruby 2.6.6
Rails 6.0

#実装
1.モデルを作る

ターミナル
rails g model tag name:string
ターミナル
rails g model tweet_tag_relation tweet:references tag:references

カラムが空で保存されるのを防ぐために、null: false を先ほど作成したマイグレーションファイルに追加する。

db/migrate/20210101000000_create_tags.rb
class CreateTags < ActiveRecord::Migration[6.0]
  def change
    create_table :tags do |t|
      t.string :name, null: false #null; falseをnameが空で保存されないように追加
      t.timestamps
    end
  end
end
ターミナル
rails db:migrate

2.アソシエーションとバリデーションを書く

tweet.rb
has_many :tweet_tag_relations, dependent: :destroy
has_many :tags, through: :tweet_tag_relations, dependent: :destroy

上記を追加

tag.rb
class Tag < ApplicationRecord
   has_many :tweet_tag_relations, dependent: :destroy
   has_many :tweets, through: :tweet_tag_relations, dependent: :destroy
end

上記の通り記述

tweet_tag_relation.rb
class CafeTagRelation < ApplicationRecord
  belongs_to :tweet
  belongs_to :tag
end

上記の通り記述

3.コントローラー
createアクションの中身を少し変更

tweet_controller.rb
def create
      @tweet = current_user.tweets.new(tweet_params)
        tag_list = params[:tweet][:name].split(/[[:blank:]]+/).select(&:present?)
        @tweet.user_id = current_user.id
        if @tweet.save
          @tweet.save_tag(tag_list)
          redirect_to :action => "index"
        else
          redirect_to :action => "new"
        end
    end

一応、半角スペースをあけることで、複数タグつけれるように書いています。

4.モデルに追加

tweet.rb
def save_tag(tag_list)
        current_tags = self.tags.pluck(:name) unless self.tags.nil?
        old_tags = current_tags - tag_list
        new_tags = tag_list - current_tags
          # Destroy old taggings:
          old_tags.each do |old_name|
            self.tags.delete Tag.find_by(name: old_name)
          end
          # Create new taggings:
          new_tags.each do |new_name|
            tweet_tag = Tag.find_or_create_by(name: new_name)
            self.tags << tweet_tag
          end
end

5.Viewに追加

show.html.erb
<% @tweet.tags.each do |tag| %>
    <span><%= tag.name %></span>
<% end %>

上記を追加する。

new.html.erb
<div class="field">
    <%= c.label :タグ %>
    <%= c.text_field :name, :size => 140 %>
  </div>

自分のアプリに応じて、書き方は変えてください。

ここまでで、一旦タグ投稿して、詳細ページにて表示できたと思います。

6.つけたタグから、タグ付いた投稿一覧ページに飛べるようにする

routes.rb
 resources :tags do
    get 'tweets', to: 'tweets#search'
 end
tweet_controller.rb
 def search
        @tag = Tag.find(params[:tag_id])
       @tweets = @tag.tweets.all 
 end

views/tweetsの中にsearch.html.erbを作り、

search.html.erb
<div class= tweetsearch>
<%= @tag.name %>
<% @tweets.each do |t| %>
    <div class="tweet">
      <%= t.body %>
    </div>
<% end %>
</div>
<%= link_to "Tweet一覧に戻る", tweets_path %>

以上で実装はできたかなと思います!

#もしかしたらエラー
もし、エラーでTweetのカラムにnameないやんけ!!ってエラー文が出たら、Tweetテーブルにnameのカラムを足しておいてください。タグのnameと関係はないのですが、私の場合はこれでなんか解決できました。(根本解決じゃないと思いますので参考までに)

#参考記事
railsでタグ機能を実装する

5
3
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
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?