モデル作成
$ rails g model Tag tag_name:string //Tagモデル作成
$ rails g model TagMap post:references tag:references //TagMapモデル作成
投稿画面
<%=form_with(model: @post, url: posts_path, local: true) do |f| %>
<h1>投稿する</h1>
<%= f.text_field :tag_name%>・・1
<input type="submit" value="投稿">
<% end %>
コードの解説
1・・<%= f.text_field :tag_name:この行を記述することで、フォームに入力されたタグが、params[:post][:tag_name]というパラメータとしてcreateアクションへ送信される。
コントローラの作成
def create
@post = Post.new(
content: params[:content],
user_id: @current_user.id
)
tag_list = params[:post][:tag_name].split(nil)・・1
if image = params[:post][:image]
@post.image.attach(image)
end
if @post.save
@post.save_tag(tag_list)・・2
flash[:notice] = '投稿を作成しました'
redirect_to('/posts/index')
else
render('posts/new')
end
end
コードの解説
1・・params[:post][:tag_name]はformから、@postオブジェクトを参照してタグの名前も一緒に送信するのでこの形で取得する。次にsplit(nil)で送信されてきた値を、スペースで区切って配列化する。配列化する理由はあとでこの値をデータベースに保存する際に一つずつ繰り返し処理で取り出す必要があるため。
2・・先ほど取得したタグの配列をデータベースに保存する処理をモデルファイルで行うようにする。
タグで入力した値を配列に収めてる(tag_list)を引数としてモデルファイルに渡す。
Tag_mapモデルファイルの作成
class TagMap < ApplicationRecord
belongs_to :post・・1
belongs_to :tag・・1
validates :post_id, presence: true・・2
validates :tag_id, presence: true・・2
end
コードの解説
1・・複数のPost、複数のTagに所有されるのでbelongs_toで関連付けを行う。
2・・PostとTagの関係を構築する際、2つの外部キーが存在しなければならないのでvalidatesの記述を書きます。
Tagモデルファイルの作成
class Tag < ApplicationRecord
has_many :tag_maps, dependent: :destroy, foreign_key: 'tag_id'
has_many :posts, through: :tag_maps
end
コードの解説
tag_mapsテーブルとの関連付けを行ってから、tag_mapsを通してpostsテーブルと関連づけています。Tag.postsとすれば、タグに紐付けられたPostを取得できる。
Postモデルファイルの作成
class Post < ApplicationRecord
has_many :tag_maps, dependent: :destroy
has_many :tags, through: :tag_maps
def save_tag(sent_tags)
current_tags = tags.pluck(:tag_name) unless tags.nil?・・1
old_tags = current_tags - sent_tags・・2
new_tags = sent_tags - current_tags・・3
old_tags.each do |old|
tags.delete Tag.find_by(tag_name: old)・・4
end
new_tags.each do |new|
new_post_tag = Tag.find_or_create_by(tag_name: new)・・5
tags << new_post_tag・・5
end
end
end
コードの解説
1・・先ほどcreateアクションにて保存した@postに紐付いているタグが存在する場合、タグの名前を配列として全て取得する。
2・・現在取得した@postに存在するタグから、送信されてきたタグを除いたタグをold_tagsとする。
3・・送信されてきたタグから、現在存在するタグを除いたタグをnew_tagsとする。
4・・古いタグを削除する。
5・・新しいタグの保存(tagsにpost_tagを追加して保存)
参考記事
【Rails】gemなしで投稿に対してタグ付けする機能+タグで投稿を絞り込み表示する機能の実装手順
[Ruby on rails]タグ付け機能① 複数のタグ付け
railsのself.tags << post_tagの意味