5

I looked at some of the answers 1] Include in qoutes, 2] Dont use require etc but neither of them works. Its possible the solution has changed in Rails4

I am trying to follow the tutorial here https://devcenter.heroku.com/articles/ruby-websockets#using-with-rails

It says Copy the existing ChatBackend middleware to app/middleware/chat_backend.rb in your Rails project. Then insert the middleware into your stack, defined in config/application.rb:

require 'chat_backend'
config.middleware.use ChatDemo::ChatBackend

I have the middleware defined in app/middlewares/chat_backend.rb as follows:

require 'faye/websocket'
require 'thread'
require 'redis'
require 'json'
require 'erb'

    module ChatDemo
      class ChatBackend
        KEEPALIVE_TIME = 15 # in seconds
        CHANNEL        = 'twitter-stream'
        def initialize(app)
        end
      /// DELETED CODE for simplicity
    end

Here is the application.rb

require File.expand_path('../boot', __FILE__)

require 'rails/all'
require 'chat_backend'  <= ERROR: config/application.rb:4:in `require': cannot load such file -- chat_backend (LoadError)

Bundler.require(*Rails.groups)

module MyProject
  class Application < Rails::Application

    config.middleware.use ChatDemo::ChatBackend
  end
end

How exactly do I add the middleware. Appreciate any exact code samples.

codeObserver
  • 6,521
  • 16
  • 76
  • 121

3 Answers3

5

You don't need to require anything because app is in the Rails 4.x load path.

Simple place your middleware class into app/middleware folder and add it to Rack via config.middleware.use(new_middleware, args)

For example: app/middleware/name_is_important.rb

class NameIsImportant
  # logic goes here
end

In application.rb (string):

config.middleware.use 'NameIsImportant'

Or in the environment files, for instance, development.rb (here you can use class name):

config.middleware.use NameIsImportant

Your specific case didn't work because you have tried to import (which is not necessary) not existing class. If you want from some reason encapsulate your class in the module, it has to be reflected in the path.

Add your class to the correct directory: app/middleware/chat_demo/chat_backend.rb

module ChatDemo
  class ChatBackend

  end
end

In application.rb:

config.middleware.use 'ChatDemo::ChatBackend'

However, I believe this module is unnecessary and it is the root of all your problems with adding middleware to Rack. Try to play with class in the module and without it and with different directories. Observe rack middleware output.

Wojciech Bednarski
  • 6,033
  • 9
  • 49
  • 73
  • 1
    Note, in Rails 5+ you can no longer use the String for the name of the middleware. You need to use the proper class name. Additionally, according to @rafaelfranca (Rails core), _"middleware can't be in app because they can't be reloaded. They should be in lib and if you put them in lib, require_relative will work."_ https://github.com/rails/rails/issues/25525#issuecomment-479941866 – Joshua Pinter Nov 02 '20 at 02:57
1

Typically Rack middleware is inserted into a Rails application by declaring it inside config/application.rb. You may need to require 'something' in the header of that file, then inside the application config block, config.middleware.use Rack::MiddlewareName as illustrated below.

If the middleware comes from a gem, your Gemfile may require it automatically so the require line may be redundant.

require 'bouncy_module'

module Coachpage
  class Application < Rails::Application
    config.i18n.enforce_available_locales = true
    # other config options

    config.middleware.use Rack::Bouncy
  end
end
Topher Hunt
  • 4,404
  • 2
  • 27
  • 51
  • Thanks @Topher. I still get the load error. I added more code and also the line where I get the error in application.rb . Any suggestions? – codeObserver Aug 02 '15 at 18:47
-1

I ended up including explicitly by filename in application.rb

require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(*Rails.groups)

module MyProject
  class Application < Rails::Application

    require File.join(Rails.root, 'app/middlewares/chat_backend.rb')
    config.middleware.use ChatDemo::ChatBackend
  end
end
codeObserver
  • 6,521
  • 16
  • 76
  • 121
  • This is very awkward solution. And is wrong, because you are loading class which is inside module, but you enforce load from wrong path. All stuff in Rails which is in the module is nested in the correct directory. Look any API, routes, etc. – Wojciech Bednarski Aug 12 '15 at 12:29