Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: How to access current controller in an Observer?

I need to access the current controller or flash a notice from an observer method.

class SomeObserver < ActiveRecord::Observer
    observe :some_model
    cattr_accessor :current_controller

    def after_create(record)
        ...
        current_controller.flash[:notice] = "Some message!"
    end
end

class ApplicationController < ActionController::Base
    before_filter do
        SomeObserver.current_controller = self
    end
    ...
end
like image 678
Andrey Dzhukov Avatar asked Nov 15 '11 18:11

Andrey Dzhukov


2 Answers

As others have stated, accessing the controller from an observer somewhat violates the MVC principle. Also the given answers fit your specific use case.

But if you need a more general solution you might try to adapt the way Rails Sweepers are working.

Sweepers are ordinary observers, but they provide access to the controller, if the observer is called from a controller action.

This is achieved by using the sweeper as both observer and controller filter simultaneously, which is easily possible because observers are singletons (i.e. they include the Singleton module)

In a nutshell, you have to do this:

  1. Create your observer as usual.
  2. Add the singleton instance as around_filter to your controller:

    class ApplicationController < ActionController::Base
      around_filter MyObserver.instance #, only: [...]
    end
    
  3. Add the methods for the filter to your observer:

    attr_accessor :controller
    
    def before(controller)
      self.controller = controller
      true #Don't forget this!
    end
    
    def after(controller)
      self.controller = nil
    end
    

Now you can access the controller from the observer callbacks. However controller is nil if the observer was triggered outside a controller action.

like image 123
Daniel Rikowski Avatar answered Sep 29 '22 08:09

Daniel Rikowski


Accessing Controller from Observer violates MVC pattern. The way to do it without violating MVC is to assign flash[:notice] from controller after calling SomeModel.create().

like image 25
buru Avatar answered Sep 29 '22 07:09

buru