Skip to content

Instantly share code, notes, and snippets.

@ecin
Last active December 20, 2015 08:19
Show Gist options
  • Save ecin/6100136 to your computer and use it in GitHub Desktop.
Save ecin/6100136 to your computer and use it in GitHub Desktop.
How to add a Rails routes helper (tightly-coupled version).
# config/initializers/extensions/action_dispatch/routing/mapper.rb
module ActionDispatch
module Routing
class Mapper
module Resources
alias_method :old_add_route, :add_route
def add_route(action, options)
if @scope[:throttle]
throttlers = @scope.delete(:throttle)
throttlers.each do |throttler|
throttle_options = options.dup
throttle_options[:constraints] = throttler.method(:matches?).to_proc
throttle_options[:to] = throttler.method(:call).to_proc
old_add_route(action, throttle_options)
end
end
old_add_route(action, options)
end
end
module Scoping
def throttle(throttler)
scope(:throttle => throttler) { yield }
end
private
def merge_throttle_scope(parent, child)
merged = parent ? parent.dup : []
merged << child if child
merged
end
end
end
end
end
# config/routes.rb
Your::Application.routes.draw do
class IPThrottler
class << self
@cache = {}
attr_reader :cache
end
def initialize(ttl = 1.seconds)
@ttl = ttl
end
def matches?(request)
cache[request.ip] ||= Time.now
# If @ttl time hasn't passed since the last request, throttle it.
Time.now - cache[request.ip] > @ttl
end
def call(env)
[429, {}, "Too Many Requests"]
end
def cache
self.class.cache
end
end
# Return 429 status code if 2 seconds haven't passed since the last request (per IP)
throttle IPThrottler.new(2.seconds) do
get "/expensive", "application#expensive_action"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment