我有一个标准的 Rails 应用程序。
创建提示时,我想为每个对该提示感兴趣的用户创建一条消息。
这听起来很简单吧?它应该是...
所以,我们从一个 Tip Observer 开始:
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
现在它运行(!)和输出:
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)
嗯,没有明显的解决方法。但是在阅读了一些聪明的木屐建议后,Sweepers 与 Observers 相同,但可以访问 url 助手。因此,让我们将 Observer 转换为 Sweeper 并删除 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 呈现为视图——这有两个好处——首先,“视图”内容被放置在正确的位置,它可能有助于我们避免这些 *_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?
任何提示建议或建议都会非常感激,我已经把头撞在这堵砖墙上好几天了,慢慢失去了生活的意愿。
蒂亚
基思