🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Q&A

1回答

1389閲覧

Formオブジェクト updateが全てに適用されてしまいます

shunxile

総合スコア26

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

0グッド

0クリップ

投稿2021/02/04 07:20

編集2021/02/05 00:00

前提・実現したいこと

投稿したものをupdateしようとすると今までに投稿したものが
全て同じものに更新されてしまってます。
指定した投稿記事のみを更新できるようにしたいです。
よろしくお願いします。

発生している問題・エラーメッセージ

エラーメッセージ NoMethodError in MessagesController#update undefined method `id' for #<Array:0x00007fb3a1cdff58>

エラーメッセージがでた後Topページなどにいくとデータが全て更新されている
きちんとメッセージが指定できていないのではないかと思うがどのようにすればいいか分かりません

該当のソースコード

Ruby

1messages_controller 2 def edit 3 @message = Message.find(params[:id]) 4 tag = @message.tags 5 if current_user.id != @message.user.id 6 redirect_to root_path 7 end 8 end 9 10 def update 11 @message = Message.find(params[:id]) 12 @message = MessageTag.new(update_message_params) 13 @message = @message.update 14 end 15 16 private 17 def message_params 18 params.require(:message_tag).permit(:title, :message, :whom, :open_plan, :name, :video, images: []).merge(user_id: current_user.id) 19 end 20 21 def update_message_params 22 params.require(:message).permit(:title, :message, :whom, :open_plan, :name, :video, images: []).merge(user_id: current_user.id) 23 end

Ruby

1message.rb 2class Message < ApplicationRecord 3 belongs_to :user 4 has_many_attached :images 5 has_one_attached :video 6 has_many :message_tag_forms, dependent: :destroy 7 has_many :tags, through: :message_tag_forms 8end

Ruby

1tag.rb 2class Tag < ApplicationRecord 3 has_many :messages, through: :message_tag_forms 4 has_many :message_tag_forms 5 validates :name, uniqueness: true 6end

Ruby

1message_tag_form.rb 2class MessageTagForm < ApplicationRecord 3 belongs_to :message 4 belongs_to :tag 5end

Ruby

1class MessageTag 2 3 include ActiveModel::Model 4 include ActiveModel::Attributes 5 include ActiveRecord::AttributeAssignment 6 attr_accessor :title, :whom, :open_plan, :message, :images, :video, :name, :user_id 7 8 with_options presence: true, length: { maximum: 50 } do 9 validates :title 10 validates :whom 11 end 12 13 with_options presence: true do 14 validates :message, length: { maximum: 200 } 15 validates :open_plan 16 validates :user_id 17 validates :name, length: { maximum: 20 } 18 end 19 20 def save 21 @message = Message.create(title: title, whom: whom, open_plan: open_plan, message: message, images: images, video: video, user_id: user_id) 22 tag = Tag.find_or_create_by(name: name) 23 24 @message_tag = MessageTagForm.create(message_id: message.id, tag_id: tag.id) 25 end 26 27 def update 28 @message = Message.update(title: title, whom: whom, open_plan: open_plan, message: message, images: images, video: video, user_id: user_id) 29 tag = Tag.find_or_create_by(name: name) 30 binding.pry 31 if MessageTagForm.update(message_id: message.id, tag_id: tag.id) 32 return redirect_to root_path 33 else 34 render :edit 35 end 36 end 37end

Ruby

1edit.html.erb 2<div class="new-message"> 3 <h1>残したい想い</h1> 4 <%= form_with model: @message, local: true do |f| %> 5 <%= render 'shared/error_messages', model: f.object %> 6 <div class="posting-form"> 7 <div class="form"> 8 タイトル 9 <span class="indispensable">必須</span> 10 </div> 11 <%= f.text_field :title, class:"form-title", id:"form-title", placeholder:"タイトル名(必須 50文字以内)", maxlength:"50" %> 12 <div class="form"> 13 メッセージ 14 <span class="indispensable">必須</span> 15 </div> 16 <%= f.text_area :message, class:"form-message", id:"form-message", placeholder:"メッセージ内容(必須 200文字以内)例)20年後の子供の誕生日に見て欲しい動画です。" ,rows:"5", maxlength:"200" %> 17 <div class="form"> 18 誰に対してか 19 <span class="indispensable">必須</span> 20 </div> 21 <%= f.text_field :whom, class:"form-whom", id:"form-whom", placeholder:"誰に宛てたものか(必須 50文字以内)例)20年後の子どもたちへ", maxlength:"50" %> 22 <div class="form"> 23 開封予定日 24 <span class="indispensable">必須</span> 25 </div> 26 <div class="form-open-plan"> 27 <%= raw sprintf( 28 f.date_select( 29 :open_plan, 30 class: 'open-plan-object', 31 use_month_numbers: true, 32 prompt:'--', 33 start_year: (Time.now.year), 34 end_year: (Time.now.year + 100), 35 date_separator: '%s'), 36 "<p> 年 </p>", "<p> 月 </p>") + "<p> 日 </p>" %> 37 </div> 38 <div class="form-caution"> 39 ※※※画像か動画どちらか1つの投稿にしてください。※※※ 40 </div> 41 <div class="image-form"> 42 <div class="form"> 43 届ける想い(画像) 44 </div> 45 <div class="click-upload"> 46 <p>クリックしてファイルをアップロード</p> 47 <%= f.file_field :images, name: 'message[images][]', id:"form-image" %> 48 <div id="image-list"></div> 49 </div> 50 </div> 51 <div class="video-form"> 52 <div class="form"> 53 届ける想い(動画) 54 </div> 55 <div class="click-upload"> 56 <p>クリックしてファイルをアップロード</p> 57 <%= f.file_field :video, id:"form-video" %> 58 </div> 59 </div> 60 <div class="tag-form"> 61 タグ 62 </div> 63 <%= f.text_field :name, id:"form-tag", placeholder:"誕生日", maxlength:"20"%> 64 </div> 65 <div class="message-btn-contents"> 66 <%= f.submit "想いを更新する" ,class:"message-btn" %> 67 <%= link_to 'もどる', root_path, class:"back-btn" %> 68 </div> 69 <% end %> 70 71</div>
pry(#<MessageTag>)> @message => [#<Message:0x00007fb3a210e0e8 id: 20, title: "テスト", whom: "新規投稿テスト", message: "新規投稿テスト", open_plan: Sat, 06 Jun 2026, encrypted_password: nil, user_id: 1, created_at: Sun, 10 Jan 2021 21:49:47 UTC +00:00, updated_at: Thu, 04 Feb 2021 06:18:56 UTC +00:00>, #<Message:0x00007fb3a210e020 id: 21, title: "テスト", whom: "新規投稿テスト", message: "新規投稿テスト", open_plan: Sat, 06 Jun 2026, encrypted_password: nil, user_id: 1, created_at: Sun, 10 Jan 2021 21:50:59 UTC +00:00, updated_at: Thu, 04 Feb 2021 06:18:56 UTC +00:00>, #<Message:0x00007fb3a210df58 : pry(#<MessageTag>)> @message_tag => nil

追記

edit.html.erbで@messageを@message_tagにした時のエラー発生部分のファイル

error_message.html.erb <% if model.errors.any? %> <div class="error"> <ul> <% model.errors.full_messages.each do |message| %> <li class="error-message"><%= message %></li> <% end %> </ul> </div> <% end %>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

質問に対する直接的な回答としては、MessageTag#update の一行目で Message.update しているからじゃないかなと思います。Message の ID を使っていないので全件更新みたいになっちゃってます。

すいません、これだいぶ混乱する。。。

  • エラーが発生するのはどの行ですか?updateアクションの一行目かな?
  • updateアクションの一行目が機能していない(二行目でインスタンス変数が上書きされてる)のでは?
  • フォームオブジェクトとは具体的にどのクラスですか?すいません、これがすごい分かりづらいです。

名前からしてフォームオブジェクトっぽいのは MessageTagForm ですが、これは Message と Tag を多対多で結合するために使用されるリレーションテーブルのモデルなので、名称的には MessageTag とかになるのが普通。
MessageTag が内容見るからにフォームオブジェクトっぽいけど、なぜか edit.html.erb のフォームで使われていない。update のフォームで使われているか分からないけど update_message_params 見る限り使われていなさそう。
フォームオブジェクトというのは文字通り、Webページのフォームを表現するために使われるのが一般的で、実際そうした方が使いやすいです。Message と Tag を両方いっぺんに更新したいという目的にフォームオブジェクトを導入するのは良いやり方だと思いますが、チグハグになっちゃっているので整理した方が良い状態です。
このまま強引に進めると、今回にみたいに想定外の動作が起きたときに、さらに何が悪いのか分からなくなってきます。

いっぺんにやりすぎて混乱しちゃってるように見えるので、まずは Message だけを新規追加、更新するところから初めてはどうでしょうか?
その上で、多対多の関係にあるタグ付けの機能を足していきましょう。

投稿2021/02/04 21:52

編集2021/02/04 21:56
oakbow

総合スコア227

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shunxile

2021/02/05 10:46

>>okabowさん 回答ありがとうございます。 エラーが発生するのはどの行ですか?updateアクションの一行目かな? message_tag.rbのupdateアクションの3行目binding.pryが記述してある次の行ifの部分です。 updateアクションの一行目が機能していない(二行目でインスタンス変数が上書きされてる)のでは? まず更新したい情報を呼びだして https://teratail.com/questions/291532 こちらを参考にupdateを行うために ``` @message = MessageTag.new(update_message_params) @message = @message.update ``` と記述しました。 フォームオブジェクトとは具体的にどのクラスですか?すいません、これがすごい分かりづらいです。 フォームオブジェクトはmessage_tag.rbです editで使用というのは <%= form_with model: @message_tag, local: true do |f| %> という記述になるということでしょうか? @messageから@message_tagにした時は <% if model.errors.any? %>の部分で NoMethodError undefined method `errors' for nil:NilClassが発生します。
oakbow

2021/02/05 11:26

>message_tag.rbのupdateアクション アクションというのはコントローラのメソッドのうち実際に画面描画に使用されるものの特別な名称です。 message_tag.rbはコントローラではないので、単にupdateメソッドと呼びます。
oakbow

2021/02/05 11:38 編集

初心者のコードは参考にしては行けません。フォームオブジェクトの使い方が間違っていますし、泥沼に陥りつつあります。 回答に書いた通り、まずはフォームオブジェクトを使用せずにMessage単体の更新処理を実装しましょう。 で、updateアクション一行目のこれ @message = Message.find(params[:id]) が機能していないと思います。二行目で上書きされています。 対象のメッセージを指定しているつもりなんだと思いますが、二行目で上書きしているので指定できていないです。
oakbow

2021/02/05 11:37

>NoMethodError undefined method `errors' for nil:NilClassが発生します。 フォームオブジェクトとしてまだ不完全だからですね。 form_withの対象モデルを変更すれば良いというのは合っているのですが、それを変えれば終わるというほど修正箇所が少ないわけではないです。 あまりよくないコードを手本に書いたのかなとちょっと想像していたんですが、そうしてしまうと修正箇所が多くなってしまい、「なぜそう修正する必要があるのか」も理解しづらいんじゃないかと思います。 ただ、真っ当に動くように修正し、今後も機能追加や改修を行うことを考えると、Message単体更新の機能をまずきちんと作り終えてからフォームオブジェクトに進むステップを踏んだ方が、回り道に見えて結局近道だと思いますよ。
shunxile

2021/02/05 13:24

>>okabowさん そうだったんですね。よく分かりました。 ありがとうございます。 仰られた通り「なぜ」がいまいち理解できないというのは確かに感じてました。 フォームオブジェクト使用前のタグがない状態では確かに更新機能はしっかりと作動していたので 1度フォームオブジェクトを使ってない時の状態に戻したいと思います。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問