LoginSignup
0
0

More than 1 year has passed since last update.

formオブジェクト(ActiveModel)を用いたタグ機能(複数投稿編)

Posted at

説明

自分はformオブジェクトを用いてタグ機能は実装したのですが、投稿はともかく編集、削除、検索などは記事が少なく、あっても複雑で苦労したのでいくつかに分けて投稿したいと思います。

前提条件

あくまで記事が少なく複雑な部分をアウトプットしたので、ルーティング、コントーラー、モデル、アソシエーションなどは記載しますが、作る手順は省略します

完成コード

tweets_controller.rb
def new
    @tweet = TweetsTag.new
end

def create
    @tweet = TweetsTag.new(tweet_params)
    tag_list = params[:tweets_tag][:name].split(',')
    if @tweet.valid?
      @tweet.save(tag_list)
      redirect_to :root
    else
      render new_tweet_path
    end
end

private

def tweet_params
    params.require(:tweets_tag).permit(:title, :image, :text, :job_id, :status_id, :name).merge(user_id: current_user.id)
  end
tweets_tag.rb
def save(tag_list)
    tweet = Tweet.create(title: title, text: text, image: image, job_id: job_id, status_id: status_id, user_id: user_id)

    tag_list.each do |tag_name|
      tag = Tag.where(name: tag_name).first_or_initialize
      tag.save

      TweetTagRelation.create(tweet_id: tweet.id, tag_id: tag.id)
    end
  end
_tweet_new.html.erb
<div class="field">
    <%= f.label :name, "タグ(タグ同士の間には半角の「,」を入れてください)", {class: 'motivate-label'} %><br />
    <%= f.text_field :name, placeholder: "(例)ドラマ,医療,社会", :class => 'motivate-field' %>
  </div>

コード解説

tweets_controller.rb
def new
    @tweet = TweetsTag.new
end

まずコントローラーに新規投稿用の空のインスタンスを作ってあげます。以前はTweetモデルから作っていたと思いますが、それをformオブジェクト用に作ったモデルを指定して作ります。

_tweet_new.html.erb
<div class="field">
    <%= f.label :name, "タグ(タグ同士の間には半角の「,」を入れてください)", {class: 'motivate-label'} %><br />
    <%= f.text_field :name, placeholder: "(例)ドラマ,医療,社会", :class => 'motivate-field' %>
  </div>

投稿ページにてタグを入力する部分を追加します。:nameの部分は自分のtagsテーブルのカラム名にしましょう。またタグを複数投稿にしたい場合は入力説明に複数投稿の際区切る指示を記載しておきましょう。自分の場合はタグ同士は半角の「,」で区切るようにこの後設定するのでそのように記載しています。

tweets_controller.rb
def new
    @tweet = TweetsTag.new
end

def create
    @tweet = TweetsTag.new(tweet_params)
    tag_list = params[:tweets_tag][:name].split(',')
    if @tweet.valid?
      @tweet.save(tag_list)
      redirect_to :root
    else
      render new_tweet_path
    end
end

private

def tweet_params
    params.require(:tweets_tag).permit(:title, :image, :text, :job_id, :status_id, :name).merge(user_id: current_user.id)
  end

1.先ほどの投稿画面で送信して内容は一般的な投稿機能のようにcreateアクションに送られます。違うのは、privateにformオブジェクト用のparamsのメソッドを作成します。requireにはformオブジェクトのモデルを指定します。加えて、permitにtagsテーブルのカラムのnameを追加してます。

2.1で作ったtweet_paramsを使って、新たなformオブジェクトのインスタンスを生成し、@tweetに代入します。そして、送信されたタグを一個づつtag_listに配列として代入していきます。

params[:tweets_tag][:name].split(',')

の部分はparamsが二重の配列になっているので:tweets_tagのname配列の中身をは.split(',')によって「,」が入力されている部分で区切って分けるという記述です。

3.@tweet.valid?を通った場合いよいよ保存です。

@tweet.save(tag_list)

の記述によって配列として一つ一つタグが入っているtag_listを引数として持っていてsaveを行いますが、このまま普通のsaveをして意味がないのでformオブジェクトのモデル内に正しく保存できるように新たなsaveメソッドを定義します。

tweets_tag.rb
def save(tag_list)
    tweet = Tweet.create(title: title, text: text, image: image, job_id: job_id, status_id: status_id, user_id: user_id)

    tag_list.each do |tag_name|
      tag = Tag.where(name: tag_name).first_or_initialize
      tag.save

      TweetTagRelation.create(tweet_id: tweet.id, tag_id: tag.id)
    end
  end

ここでまず、tweetモデルにだけツイート内容を作る作業を行います。

    tweet = Tweet.create(title: title, text: text, image: image, job_id: job_id, status_id: status_id, user_id: user_id)

この記述はtweetモデルの各カラムを指定してattr_accessorに書いた内容を保存しています。

 tag_list.each do |tag_name|
      tag = Tag.where(name: tag_name).first_or_initialize
      tag.save

      TweetTagRelation.create(tweet_id: tweet.id, tag_id: tag.id)
    end

この部分では引数によって持ってきたtag_listの中身を一つ一つ取り出して、初めてのものならtagsテーブルに保存、tagとtweetとの中間テーブルにも保存するといった記述です。

まとめ

以上が複数タグを保存する記述の解説となります。この後編集、削除、フロント、タグ関連の投稿一覧、タグの検索の記事を投稿していこうと思います。閲覧ありがとうございました。

0
0
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
0
0