はじめに
タグ機能実装中に、Formオブジェクトが絡んだタグの更新にとても苦戦したことと、しっくりくる記事が少なかったこともあったので執筆します。完全自作かつ非効率な実装方法かもしれませんがどうぞお付き合いください。
なお、もっとこうしたら簡単だよ!みたいなコメントをくださると嬉しいです。
#タグの更新で苦戦した部分
まず、今回苦戦したポイントとして、「Formオブジェクトはレコードとしては存在していない」というところです(あと、複数タグという点)。通常、なにかしらの更新をする際にはfindメソッドあるいはfind_byメソッドをつかって、欲しいデータを持ってくることができたはずです。
Formオブジェクト(例:item_address.rb)は実際にレコードがあるわけではないので、以下のようにはできません。
@item_address=ItemAdress.find(id:params[:id])
#解決策
じゃあ、どうすればいいのか。
答えは、newメソッドを使います。「レコードとして存在しない」は言い換えれば「指定する必要もない」ということで持ってくる必要はないので、だったらそのときに作ればよくね?って話です。
(ここまで意味が不明だと思いますが、お付き合いください)
Formオブジェクトについてしっかりとした理解があれば、以下のコードを見れば理解できると思います。
def edit
@tweets_tag=TweetAddress.new(title:@tweet.title,content:@tweet.content)
end
まずはeditアクションに着目してみましょう。たしかに、newメソッドを使用しています。でも、これでしっかり欲しいデータが詰まったインスタンスが生成されます。実はFormオブジェクト自体はnewで作成されますが、Formオブジェクトの中身には、@tweetというbefore_actionでparams[:id]からfindメソッドで指定したインスタンスがデータとして入っているので、結果として指定したいFormオブジェクトが出来上がっているわけです。
あとは、@tweets_tagを使えば編集ページは表現できます。
updateアクションの実装
引き続いて、編集ページで新たにタグが入力されたとします。そのとき、updateアクションはどのように記載すべきでしょうか。
これについては、コードを見た方が早いので以下を見てください。
#省略
def update
@tweets_tag=TweetsTag.new(update_params)
tag_list=params[:tweets_tag][:name].split(",")
if @tweets_tag.valid?
@tweets_tag.update(tag_list)
redirect_to tweet_path(@tweet)
else
render :edit
end
end
#省略
def update(tag_list)
#tweetの更新
@tweet = Tweet.where(id: tweet_id)
tweet = @tweet.update(title: title,content: content)
@old_relations=TweetTagRelation.where(practice_id:practice_id)
#この時点で一旦中間テーブルのデータ消す
@old_relations.each do |relation|
relation.delete
end
#tagの更新
tag_list.each do |tag_name|
@ptag = Tag.where(name: Tag_name).first_or_initialize
@Tag.save
#再度1個づつ中間テーブルへ登録
new_relation=TweetTagRelation.new(tweet_id:tweet_id,ptag_id:@tag.id)
new_relation.save
end
end
ここでも、editアクション同様にnewメソッドとストロングパラメータを使って、インスタンスを持ってきていますね。
updateでのポイントは、自らでupdateメソッドを実装しないといけないところですね.流れとしては、tweetとtagをそれぞれ更新すると同時に、新たな中間テーブルのレコードを作成するようにするupdateメソッドをtweet_tag.rbに記載します。本当は既存の中間テーブルのレコードを消さずに更新できればもっと効率が上がるのですが、とりあえず今回は実装完了を目標としていますのでそこは割愛します。
なお、入力されたタグはparamsの中では1つの文字列として認識されますので、複数タグを入力するときは「,」で区切ってもらい、受け取った後にsplitメソッドで分割することに注意してください。
tag_list=params[:tweets_tag][:name].split(",")
おわりに
私自身も実装にかなり時間がかかってしまったのですが、終わってみるととてもシンプルでした。Formオブジェトパターンが関わると見慣れない記述方法も出てくるので、焦ってしまいがちですが、一呼吸おいてから考えてみるととてもシンプルで、Railsのすごさを感じれました!!!!