5

I have an observer which looks like this:

class CommentObserver < ActiveRecord::Observer
    include ActionView::Helpers::UrlHelper

    def after_create(comment)
        message = "#{link_to comment.user.full_name, user_path(comment.user)} commented on #{link_to 'your photo',photo_path(comment.photo)} of #{comment.photo.location(:min)}"
        Notification.create(:user=>comment.photo.user,:message=>message)
    end

end

Basically all I'm using it to do is create a simple notification message for a certain user when someone posts a comment on one of their photos.

This fails with an error message:

NoMethodError (undefined method `link_to' for #<CommentObserver:0x00000102fe9810>):

I would have expected including ActionView::Helpers::UrlHelper would solve that, but it seems to have no effect.

So, how can I include the URL helper in my observer, or else render this some other way? I would happily move the "message view" into a partial or something, but an observer has no associated views to move this to...

Andrew
  • 42,517
  • 51
  • 181
  • 281

3 Answers3

3

Why aren't you building the message when it's rendered out to the page and then caching it using something like this?

<% cache do %>
  <%= render user.notifications %>
<% end %>

This would save you having to do a hack in the observer and would be more "standards compliant" in Rails.

Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261
  • This isn't necessarily going to send an email. I'm trying to create a simple model that can be used to create a notice (like the one on stack overflow when someone posts an answer to your question). Depending on a user's settings the Notification can email the message or just put it on a users dashboard. This observer is simply creating a notification message pertinent to a comment being created. If you have a better suggestion for the whole system let me know, this has been killing me today and I haven't been able to find a good example of this kind of notification system to study. – Andrew Jun 20 '11 at 21:57
  • ...um I think you edited after I already commented... :) I have never used "cache" before -- how does that work? – Andrew Jun 20 '11 at 21:59
3

To handle this type of thing, I made an AbstractController to generate the body of the email, then I pass that in as a variable to the mailer class:

  class AbstractEmailController < AbstractController::Base

    include AbstractController::Rendering
    include AbstractController::Layouts
    include AbstractController::Helpers
    include AbstractController::Translation
    include AbstractController::AssetPaths
    include Rails.application.routes.url_helpers
    include ActionView::Helpers::AssetTagHelper

    # Uncomment if you want to use helpers 
    # defined in ApplicationHelper in your views
    # helper ApplicationHelper

    # Make sure your controller can find views
    self.view_paths = "app/views"
    self.assets_dir = '/app/public'

    # You can define custom helper methods to be used in views here
    # helper_method :current_admin
    # def current_admin; nil; end

    # for the requester to know that the acceptance email was sent
    def generate_comment_notification(comment, host = ENV['RAILS_SERVER'])
        render :partial => "photos/comment_notification", :locals => { :comment => comment, :host => host }
    end
  end

In my observer:

  def after_create(comment)
     email_body = AbstractEmailController.new.generate_comment_notification(comment)
     MyMailer.new(comment.id, email_body)
  end
Dex
  • 12,527
  • 15
  • 69
  • 90
2

So, it turns out this cannot be done for the same reason you can't use link_to in a mailer view. The observer has no information about the current request, and therefore cannot use the link helpers. You have to do it a different way.

Andrew
  • 42,517
  • 51
  • 181
  • 281