简体   繁体   中英

Access controller method in a Ruby module

In my Rails app, there is a method defined in the ApplicationController that I need to use in a module. This module also needs to be accessible to all controllers/helpers. I'm not sure what the best way is to give the module access to this method. I figure that there is a way to do it by wrapping the module and then including it into the ApplicationController.

I also want to retain the namespacing instead of including the module methods right into the controller. eg controller.Module.foo instead of just controller.foo

This is what I'm trying to do:

module Analytics
  module Events
    extend self

    def create_event name
      # do some stuff
      controller_method name
    end
  end
end

class ApplicationController < ActionController::Base
  include Analytics

  def controller_method
     # ...
  end

  def some_other_method
    Events.create_event :test
  end
end

Now I know I can add a self.included method to the Analytics module which gives me the passed in base object, but I don't know how I can make use of that base in the KissMetrics module.

Is this possible or is there a better way of doing this?

Edit:

To further clarify, I am using a gem that is extended/included into ActionController::Base. See bottom of this script . This library is then configured inside the ApplicationController. All I want to do is have a module with defined events that makes use of this gem. It makes it easier for me to have consistent events across all my controllers eg

module Events
  def sign_up_event
    analytical.event "sign up" # calls the library that was loaded into the app controller
  end
end

# in some controller
Events.sign_up_event
# instead of this, which is totally usable but not DRY
analytical.event "sign up"

As far as my knowledge goes, you shouldn't call a controller action from a lib but the other way around.

I suggest making a library as I do not know exactly what you are trying to build I've setup an example:

in lib/analytics.rb

class Analytics
  def initialize(object_id, event_id)
    # insert object to event relation logic here
    @object = Object.find(object_id)
    @event = Event.find(event_id)
  end

  def add_instance_method
    # add logic for instantiated Analytics object
    @object.event_collection.create(event_id: @event.id)
  end

  def self.check_class_method?(object_id, event_id)
    # check logic for Analytic Class taking 2 arguments
    @object = Object.find(object_id)
    @event = event.find(event_id)
    @object.events.include?(@event)
    # return true/false
  end
end

so now in your controller:

def action
  @object = Object.find(params[:id])
  @event = Event.find_by_identifier("logged_in")

  unless Analytics.check_class_method?(@object_id, @event_id)
    analytic = Analytics.new(@object.id, @event.id)
    raise "Failed" unless analytic.add_instance_method
  end
end

Decided to solve this by changing the module into a class and instantiating it in a before_filter callback in ApplicationController. I pass it the initialized analytical object and all is good. Would have preferred using a module but this does the trick.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM