タグ付け機能[バックエンド]
What
タグ付け機能の実装例を紹介します。
DB テーブルはこんな感じ。
Strategy
文字列 (タグ) をparamsで保管しておいて、mapメソッドで都度都度保存
その時に、中間テーブルにもデータを入れておく
このようにすれば、元からあるWorkテーブルと無関係にタグを実装できます。
Solution
モデル側の記述
中間テーブルを作成する関係上、以下のように定義しておきます。
バリデーションや依存関係 (dependent系) はよしなに。
# work.rb class Work < ApplicationRecord has_many :tag_works has_many :tags, through: :tag_works end
# tag.rb class Tag < ApplicationRecord has_many :tag_works has_many :works, through: :tag_works end
# tag_work.rb class TagWork < ApplicationRecord belongs_to :work belongs_to :tag end
view側の記述
私の場合は、works tableに新しくレコードを追加するときに、タグも保存しておきたかったので、form_with(model: @work)内に追記しました。
記事とか画像とかが元々投稿できていたら、form_with内に何か足したりする必要はありません。
= form_with(model: @work, url: '/new', local: true) do |f| ... = f.text_field :all_tags, class:'p-Post__box', required: true ...
コントローラー側の記述
コントローラーを触りますが、送信ボタンを押した時に、paramsに値が入っているか確かめましょう。
def new @work = Work.new end def create binding.pry @work = Work.new(pile_create_params) if @work.save else ... end end
ターミナルで、paramsと打ちます。
> params >> ... "work" => {"..." => "...", ..., "all_tags" => "..."}
params[:work][:all_tags]とかparams.require(:work).permit(:all_tags)などと打てば、入力したタグが取り出せると思います。 それをprivateメソッド以下にtag_paramsとして定義してやります。
これでタグ入力した値を取得できました。
private def tag_params params.require(:work).permit(:all_tags) end
タグが1個だけの場合は、そのまま保存すれば完成です。 例えば、以下のように書いてやります。
def create @work = Work.new(pile_create_params) if @work.save tag = Tag.find_or_create_by!(name: tag_params[:all_tags].name) TagWork.find_or_create_by!(tag_id: tag.id, work_id: @work.id) end end
タグが複数の場合は何で区切るかを決める必要があります。
例えば、#で区切ることを考えます。
splitメソッドで文字列を#毎に区切り配列にします。
tag_params[:all_tags].split("#")
あとはmapメソッドで同じ処理を繰り返せば、完成です。
合わせるとこんな感じになります。
stripメソッドで空白を消すのもありです。
def create @work = Work.new(pile_create_params) if @work.save tag_params[:all_tags].split("#").map do |name| tag = Tag.find_or_create_by!(name: name.strip) TagWork.find_or_create_by!(tag_id: tag.id, work_id: @work.id) end redirect_to root_url else ... end end