質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

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

Ruby on Rails

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

Q&A

解決済

1回答

2498閲覧

Ruby on Railsのコールバックの挙動が分かりません。

dongw

総合スコア119

Ruby

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

Ruby on Rails

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

0グッド

0クリップ

投稿2017/04/13 06:09

編集2017/04/17 01:39

ruby:message.rb

1class message < ApplicationRecord 2 belongs_to :user 3 4 validates :title, presence: true 5 validates :content, presence: true 6 7 before_create do 8 user.messages.update_all('notice = notice + 1 ') 9 end

messagesコントローラーのcreateアクションが呼ばれる前に
before_createを使って
メッセージに基づくuserのmessagesを全部取得してupdateをかけています。
しかしこのbefore_createの中では
いきなり
user.messagesでmessageに基づくuserのmessagesが全て取ってこれています。
本来ならcurrent_user.messages.~~にしようかと思っていたのですが、これもcurrent_userがundefined methodで怒られてしまいました。

何故この記述でデータが取ってこれているのでしょうか?

追記

def new @message = Message.new end def create @message = Message.new(message_params) if @message.save redirect_to messages_path else render :new end end private def message_params params.fetch(:message, {}).permit(:title, :content).merge(user_id: current_user.id)

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

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

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

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

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

guest

回答1

0

ベストアンサー

コントローラではなくモデルですね。

before_create do user.messages.update_all('notice = notice + 1 ') end

ここで、user.messages...は、self.user.messagesと同じです。selfは自分自身、すなわち、createを呼び出したMessageモデルのインスタンスです。

m = Message.new(...) m.user.messages.update_all(...) # こういうこと m.save

current_userはおそらく「現在ログインしているユーザー」なのでしょうが、モデルの中でこれを参照するなら、current_userが指すもの(Userモデルのインスタンス)をメソッドの引数なり属性としてインスタンスに設定するなりして外部から渡す必要があります。

ただし、current_userをモデルの中で参照するというのは何かが間違っている事が多いです。userのインスタンスメソッド

class User <... def method # なにかする end end # controller current_user.method

のような形に書き換えられないか検討の余地があります。

投稿2017/04/13 11:16

編集2017/04/14 02:50
suzukis

総合スコア1449

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

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

dongw

2017/04/14 01:34

回答ありがとうございます。 モデルでした。申し訳ないです。 self.user.messagesということですが、 m = Message.new 空のインスタンス作成 m.user.messages.update_all(...) ここでm.userでデータって取ってこれるのでしょうか? アソシエーションを組んでいますが、空のインスタンスが入ったmのuserという意味になってしまうような? またmessageコントローラーのcreateアクションから呼ばれたbefore_createだから m = Message.new m.user.~~~ という動きは内部で自動で行ってくれるという認識でいいでしょうか?
suzukis

2017/04/14 02:53

(...)を書き足しましたが、もちろん適切な値が設定されてなければ.userは参照できません。 コールバックで指定したことは自動で実行されますう。そのコードは同じ動作を手で書いた場合にはどうなるかというイメージとご理解ください。
dongw

2017/04/17 01:45

すみません。理解不足な点があるので追加でお聞きします。 messageコントローラーの記述を追加しました。 回答頂いた「createを呼び出したMessageモデルのインスタンス」 という所ですが、 1.コールバックが発動する時点はcreateのアクションがすべて終わった後?それともcreateが呼ばれてすぐでしょうか? createを呼び出したmessageモデルのインスタンスはnewの@messageですが、これにはuser_idは含まれていません。ストロングパラメーターを通してようやくuser_idが追加されると思うのでやはりコールバックが起きるのはcreateアクションのコードをすべて読み終わってからなのでしょうか?
suzukis

2017/04/17 09:59 編集

「createを呼び出した」…と書いたのが誤解を招いているのかも知れませんが、ここで言っているcreateはActiveRecordのcreateです。コントローラのcreateではありません。ActiveRecordのcreateはnewしてsaveするのと同じ事なので、上記のコードであればsaveを呼んだタイミングで実際にDBに書き込みが行われる前にbefore_createコールバックが実行されます
dongw

2017/04/18 04:59

コメントありがとうございます。 勘違いしておりました。てっきちコントローラーのcreateだと・・・ saveが行われた時点であればすでにuser_idのパラメーターも入っておりコールバック先でデータを取ってこれますね。 大変勉強になりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問