2

I've written a timecard app, and I have a page where people can "punch" in and out. Each person has a button which makes an Ajax call back to change their status. A couple of folks have figured out that it's fun to click on a person's button a hundred times in a row, so that the report page for clock in/out times gets really goofy.

I'd like to put a simple Javascript function in the punch page which would limit the "clickability" of the page to something like once every 5 seconds. I've found a couple of other threads here talking about something like that, but I don't know enough about JS to graft those suggestions into how Rails is making the Ajax calls.

Community
  • 1
  • 1
David Krider
  • 886
  • 12
  • 27

4 Answers4

3

Well, there are several possibilities; depending on how much control you'd like.

First you could limit in the JS how often the request can be made. As mentioned earlier. Also, you could make it part of the model logic, not accepting updates within a certain time (also mentioned earlier)

My suggestion would be to rate limit the request per user. There is a nice rack middleware for that: http://datagraph.rubyforge.org/rack-throttle/. If needed you could add customisations, but it's a good start I think.

Bert Goethals
  • 7,867
  • 2
  • 20
  • 32
2

Couldn't you check the updated_at field on your record? It won't limit the "mouse" click rate, but it will keep your record from getting updated more than x many times per minute/hour.

For example, in your model, you could have something like:

class TimeRecord < ActiveRecord::Base
  validate :throttled_updates, on: :update

  private
  def throttled_updates
    errors.add(:updated_at, "must be more than 5 minutes ago") if self.updated_at < 5.minutes.ago
  end
end 
jerhinesmith
  • 15,214
  • 17
  • 62
  • 89
1

http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to

Option: disable-with

You can disable the button after an onclick event. The user user would have to reload the page to reclick. Otherwise you'll need some JS to re-enable after a timeout.

Reuben Mallaby
  • 5,740
  • 4
  • 47
  • 45
  • This one is actually interesting to me anyway, as my "punch" page reloads (through a tiny JS script) every 15 seconds anyway. – David Krider Jun 04 '11 at 09:34
0
# assumes you use jQuery
link_to 'Toggle', toggle_path, :remote => true, :onclick => '
    var e = $(this);
    if(e.data("busy") == "yes"){
        return false;
    } else {
        e.data("busy", "yes");
        setTimeout(function(){ 
            e.data("busy", "no");
        }, 5000);
    }
  '.gsub("\n", '')

Check http://jsfiddle.net/u42gQ/1/

clyfe
  • 23,695
  • 8
  • 85
  • 109
  • To the downvoter, if you're going to downvote somebody, you should at least explain why. Downvoting anonymously and silently helps nobody. @clyfe, you were probably downvoted because this will only work per-request, and embedding an entire block of JS inside link_to in this way is not very maintainable. You should really keep your JavaScript in a separate file and only reference the function/method in the event handler attribute. Since you're using jQuery you can even just get jQuery to bind the event to your link without tainting your markup. – d11wtq Jun 02 '11 at 23:39
  • Indeed! The sample is for illustrative purposes. The idea is to prevent the default action of the event if the "busy" flag has not yet expired. – clyfe Jun 03 '11 at 17:25
  • Well, to be fair, this _does_ answer the question of how to graft into RoR the sort of JS code I've been seeing by searching Google for an answer, so you get an upvote from me, just for the `:onclick` parameter. – David Krider Jun 04 '11 at 09:32