1

私は標準の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

キース

4

1 に答える 1

2

あなたのアプローチがRails-yではないというのは正しいです。モデル、コントローラー、およびビューのメソッドを、設計されていない方法で混在させようとしていますが、それは常に少し不安定です。

私があなたの道をたどり始めていたら、おそらく問題をあきらめてlink_to、リンクの HTML を手動でコーディングしていたでしょう。そうlink_to_tip = link_to tip.name, tip_path(tip)なりますlink_to_tip = '<a href="#{tip_path(tip)}">#{tip.name}</a>-あなたが探しているなら、迅速で汚い解決策;-)

しかし、私の経験では、Rails は非標準的な方法で処理を行う場合を除き、非常に優れています。その後、それはあなたを噛むことができます:-)

問題は、そこにあるべきではない Message モデルにテキストを書き込んで保存していることです。Message モデルbelong_to Tipsとビューは、ヒントへのリンクを含むメッセージ テキストの表示を担当する必要があります。Message が Tips 以外の何かに関するものである可能性がある場合、次のように Message モデルで多態的な関連付けを作成できます。

belongs_to :source, :polymorphic => true

Tip モデルには以下が含まれます。

has_many :messages, :as => :source

次に、これを行います (コードを例として使用します)。

m = Message.new
m.source = tip
m.save!

メッセージをレンダリングするビューは、次のようにリンクを作成する責任があります。

<%= "Hello #{u.name}, a new tip: #{link_to m.source.name, tip_path(m.source)}" %>
于 2010-08-21T21:07:19.263 に答える