How skip config.middleware.use for a specific controller action in Rails 5
Asked Answered
B

3

6

Is there a way to setup config.middleware.use to exclude / ignore / skip a specific controller action?

For example, if I wanted to exclude the Post#show controller action.

I'm using https://github.com/railslove/rack-tracker to test Google Analytics/Tag Manager.

  # Rack Tracker config
  config.middleware.use(Rack::Tracker) do
    handler :google_tag_manager, { container: ENV['GTM_CONTAINER_ID'] }
  end

I thought I could use a condition like:

  # Rack Tracker config
  config.middleware.use(Rack::Tracker) do
    handler :google_tag_manager, { container: ENV['GTM_CONTAINER_ID'] } if app.route != ApplicationController::PostController.show
  end

Any help is much appreciated.

Buckhound answered 1/2, 2017 at 13:55 Comment(0)
E
4

You can provide a lambda to the container option:

config.middleware.use(Rack::Tracker) do
  handler :google_tag_manager, { container: lambda { |env| ENV['GTM_CONTAINER_ID'] if env['REQUEST_PATH'].match(/\/posts\/\d+/) } }
end

This lambda will be evaluated in each request and give you access to the env object. With that you can return a string for the google tag manager container based on the current request path.

Erdah answered 28/9, 2018 at 20:11 Comment(0)
D
1

Middleware is called before controller logic is even reached, so there's no way to limit middleware based on actions.

That being said, middleware CAN see which route is being called and can act conditionally according to route. I did a quick google search and it looks like rack-tracker does not have a built-in option for doing this. However, you can circumvent this by wrapping this middleware in another middleware, like so:

class ConditionalTracker
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['REQUEST_PATH'].match(/\/posts\/show\/?/)
      tracker = Rack::Tracker.new(@app) do
        handler :google_tag_manager, { container: ENV['GTM_CONTAINER_ID'] }
      end
      env = tracker.call(env)
    end

    @app.call(env)
  end
end

and then:

# config/application.rb

config.middleware.use ConditionalTracker
Delisadelisle answered 1/2, 2017 at 14:49 Comment(4)
Thanks for taking the time and replying eiko. Question about the .match method, does this match the Post#show action via a route is that how that works? So if the post path is "posts/hello-world/" this would match? Trying to understand how if env['REQUEST_PATH'].match(/\/posts\/show\/?/) works. Thanks againBuckhound
Yeah, .match uses a regex to analyse the path of the incoming request. I chose /posts/show/ as a generic path because I didn't know what your routes.rb file looked like. If your posts are at the path /posts/name-of-post, then my regex won't work. Try replacing it with this: /\/posts\/[\w'-]+\/?/Delisadelisle
Hi @eiko. I finally got the regex I wanted (testing via the Rails console) but I'm getting an error when starting the app: undefined method `handler' for #<Rack::Tracker:0x007f9e4e93a6e0>, relating to tracker.handler :google_tag_manager, { container: ENV['GTM_CONTAINER_ID'] }. Is there something I'm missing in terms of running Rack Tracker within the middleware call method? Thanks againBuckhound
@WasabiDeveloper that was my mistake, the only way to set handlers in Rack::Tracker is via a block on .new. i went ahead and updated my answer with the proper syntax. let me know if it works!Delisadelisle
R
1

You can also check the values of env['action_controller.instance'].params['controller'] and env['action_controller.instance'].params['action'], so in your case:

class ConditionalTracker
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['action_controller.instance'].params['controller'] == 'posts' &&
       env['action_controller.instance'].params['action'] == 'show'
      tracker = Rack::Tracker.new(@app) do
        handler :google_tag_manager, { container: ENV['GTM_CONTAINER_ID'] }
      end
      env = tracker.call(env)
    end

    @app.call(env)
  end
end
Rockafellow answered 19/2, 2020 at 18:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.