7

I'm searching rate-limiting engine for my rails 3 application. I've found some but that's not what i need. I 've found rack-throttle gem and curbit gem. It seems that rack-throttle works for each request to rails application but i need to limit requests only to one action. Curbit was last updated two years ago. Can anyone tell me about any other rate-limiting engines that i can use? Note that it should work with caching.

roman
  • 5,100
  • 14
  • 44
  • 77

2 Answers2

13

Well, finally rack throttle is a good solution.

You can do it the following way. You need to define your custom limiter. It can be based on either of the following limiters

Rack::Throttle::Limiter
Rack::Throttle::Interval
Rack::Throttle::Hourly
Rack::Throttle::Daily

Everything you need to do is derive from one of the above classes to define custom logic. For example:

class CustomLimiter < Rack::Throttle::Interval
  def allowed?(request)
  #custom logic here
  end
end

You should put this file in the RAILS_ROOT/lib path. Then in the application.rb file you should specify what class to use as a limiter. For example if you want to apply limiter only to one action you can do it the following way:

#lib/custom_limiter.rb
class CustomLimiter < Rack::Throttle::Interval
  def allowed?(request)
    path_info = Rails.application.routes.recognize_path request.url rescue {}
    if path_info[:controller] == "application" and path_info[:action] == "check_answer"
      super
    else 
      true
    end
  end
end

#config/application.rb
class Application < Rails::Application
  ... 
  #Set up rate limiting
  config.require "custom_limiter"
  config.middleware.use CustomLimiter, :min => 0.2
  ...
end

You may need to take this into consideration

Hope this will be useful

UPD:

you may want to check out another solution: rack-attack

Community
  • 1
  • 1
roman
  • 5,100
  • 14
  • 44
  • 77
  • wrong code! change to config.require "custom_failure" – CelinHC Mar 29 '12 at 15:08
  • fixed. everything seems to be ok now – roman Apr 03 '12 at 14:55
  • 1
    Thanks for the step-by-step. Just to know a bit more about the setup. Are you using a what kind of DB to store the counters? – Eduardo Jan 02 '14 at 11:12
  • Also check out the whitelisted? and blacklisted? methods. https://github.com/datagraph/rack-throttle/blob/master/lib/rack/throttle/limiter.rb#L54-L81 – ifightcrime Apr 25 '14 at 23:54
  • Got caught on this as well. Make sure you also pass `request.request_method` as a second argument to recognize_path (ex: `recognize_path(request.url, request.request_method)`) if you want to rate limit anything other than just GET requests. – ifightcrime Apr 26 '14 at 00:56
  • You might also want to check [Rack::Defense](https://github.com/Sinbadsoft/rack-defense) ([gem](http://rubygems.org/gems/rack-defense)). – nakhli Oct 13 '14 at 07:50
2

rack-throttle does what you want. Subclass Limiter and define your own #allowed? method. Simply return true if the request isn't the action you want the limit and don't count it towards the limit. Take a look at daily.rb. Redefine #cache_set so it doesn't save those that don't match the route you want to limit.

Reactormonk
  • 21,472
  • 14
  • 74
  • 123
  • I've overrided it, and put the file in the lib directory and restarted the server but it doesn't work. `class CustomLimiter < Rack::Throttle::Limiter def allowed?(request) true == true end end` The page is opened but the assets are not loaded and i get `ERROR NoMethodError: undefined method `each' for "403 Forbidden (Rate Limit Exceeded)` So the styles are not applied. In `application.rb` i have `config.middleware.use Rack::Throttle::Interval, :min => 0.2`. What's wrong? – roman Mar 06 '12 at 10:57