私は標準のRailsアプリケーションを持っています。
ヒントを作成したら、そのヒントに関心のあるユーザーごとにメッセージを作成したいと思います。
これは簡単に聞こえますよね?そのはず...
したがって、TipObserverから始めます。
class TipObserver < ActiveRecord::Observer
def after_save(tip)
# after the tip is saved, we'll create some messages to inform the users
users = User.interested_in(tip) # get the relevant users
users.each do |u|
m = Message.new
m.recipient = u
link_to_tip = tip_path(tip)
m.body = "Hello #{u.name}, a new tip: #{link_to_tip}"
m.save!
end
end
end
エラー:
tip_observer.rb:13:in `after_save': undefined method `tip_path' for #<TipObserver:0xb75ca17c> (NoMethodError)
わかりました。TipObserverはUrlWriterメソッドにアクセスする必要があります。これは修正するのがかなり簡単なはずですよね?
class TipObserver < ActiveRecord::Observer
include ActionController::UrlWriter
これで、runs(!)と出力:
Hello dave18, a new tip: /tips/511
うまくいきました!そうですね、本当にクリック可能なリンクにしたいのです。繰り返しますが、それは簡単なはずですよね?
link_to_tip = link_to tip.name, tip_path(tip)
エラー:
tip_observer.rb:13:in `after_save': undefined method `link_to' for #<TipObserver:0xb75f7708> (NoMethodError)
では、今回はTipObserverがUrlHelperメソッドにアクセスする必要があります。これは修正するのがかなり簡単なはずですよね?
class TipObserver < ActiveRecord::Observer
include ActionController::UrlWriter
include ActionView::Helpers::UrlHelper
エラー:
whiny_nil.rb:52:in `method_missing': undefined method `url_for' for nil:NilClass (NoMethodError)
わかりました。これを追加すると、url_for宣言が妨げられたようです。インクルードを別の順序で試してみましょう。
class TipObserver < ActiveRecord::Observer
include ActionView::Helpers::UrlHelper
include ActionController::UrlWriter
エラー:
url_rewriter.rb:127:in `merge': can't convert String into Hash (TypeError)
うーん、これを回避する明確な方法はありません。しかし、いくつかの巧妙な下駄を読んだ後、スイーパーはオブザーバーと同じですが、URLヘルパーにアクセスできるという提案があります。それでは、オブザーバーをスイーパーに変換して、UrlHelperとUrlWriterを削除しましょう。
class TipObserver < ActionController::Caching::Sweeper
observe Tip
#include ActionView::Helpers::UrlHelper
#include ActionController::UrlWriter
まあ、それはそれを実行することを可能にします、しかしここに出力があります:
Hello torey39, a new tip:
したがって、エラーは発生しませんが、URLは生成されません。コンソールを使用してさらに調査すると、次のことがわかります。
tip_path => nil
したがって:
tip_path(tip) => nil
さて、私はその問題を解決する方法がわからないので、おそらく別の方向からこれを攻撃することができます。コンテンツをerbテンプレートに移動し、Message.bodyをビューとしてレンダリングすると(2つの利点があります)、最初に「ビュー」コンテンツが正しい場所に配置され、これらの*_pathの問題を回避できる可能性があります。
それでは、after_saveメソッドを変更しましょう。
def after_save(tip)
...
template_instance = ActionView::Base.new(Rails::Configuration.new.view_path)
m.body = template_instance.render(:partial => "messages/tip", :locals => {
:user=>user,
:tip=>tip
})
m.save!
end
エラー:
undefined method `url_for' for nil:NilClass (ActionView::TemplateError)
すばらしいですが、今度はこの血まみれのurl_forに戻ります。そのため、今回はActionViewが文句を言っています。次に、これを修正してみましょう。
def after_save(tip)
...
template_instance = ActionView::Base.new(Rails::Configuration.new.view_path)
template_instance.extend ActionController::UrlWriter
エラー:
undefined method `default_url_options' for ActionView::Base:Class
素晴らしいので、何をしてもエラーが発生します。私は成功せずdefault_url_options
に内部で割り当てる多くの方法を試しました。template_instance
これまでのところ、これはあまり「Railsy」とは感じていません。実際、それは実に難しいと感じています。
だから私の質問は:
- 丸い穴に四角いペグを入れようとしていますか?もしそうなら、この機能を提供するためにアーキテクチャをどのように適応させる必要がありますか?他のウェブサイトにはないものだとは信じられません。
- オブザーバーまたはスイーパーの使用をあきらめる必要がありますか?
- MessagesControllerを介して新しいメッセージを作成する必要がありますか?その場合、Observer / Sweeper内から直接かつ複数回MessagesControllerを呼び出すにはどうすればよいですか?
ヒントのアドバイスや提案は非常にありがたいことに受け取られます。私は数日間このレンガの壁に頭をぶつけてきて、ゆっくりと生きる意志を失っています。
tia
キース