Search code examples
ruby-on-railsrubyhttprequestnet-http

Ruby: Recording HTTP requests inside a custom method


I'm trying to custom record http requests. The idea is to define a function in which a request is logged.

recorded :get, :post, :patch, :delete do
  Net::HTTP.get(URI('http://www.google.com')) #will log
end

Net::HTTP.get(URI('http://news.ycombinator.com')) # will not log

The problem is that I needed to alias_method inside the Net::HTTP class and defining a class inside a method is not allowed.

Here is the method definition.

require 'net/http'

def recorded(*methods, &block)
  # module Net
  #   class HTTP
  #     alias_method(:orig_request, :request) unless method_defined?(:orig_request)
  #     alias_method(:orig_connect, :connect) unless method_defined?(:orig_connect)
  #
  #     def request(req, body = nil, &block)
  #       if started?
  #         puts :started
  #       end
  #
  #       @response = orig_request(req, body, &block)
  #       puts @response.code
  #       # LOGGING HERE THE REQUEST
  #
  #       @response
  #     end
  #
  #     def connect
  #       orig_connect
  #     end
  #   end
  # end

  yield block
end

Solution

  • You will immediately experience a lot of other problems with this approach as you have this particular problem overcame, but answering the question stated: alias_method is just a class method:

    Net::HTTP.alias_method(:orig_request, :request)
    

    the above will perfectly work. But your code then never “dealiases” it back (restores the original method,) hence any subsequent call to Net::HTTP#request will in turn call the aliased version.

    To avoid this, one might set an instance variable on class Net::HTTP, or like, to keep the state and route to either aliased method, or the original one.

    Sidenote: since Ruby2 we have Module#prepend for this purpose, using such aliases approach looks like legacy.