Now OneFeed supports commenting. Since post pages are cached for quick access, a tiny modification is needed to accept POST request initiated from the cached pages. authenticity_tokens in comment creation form of cached pages are usually out-of-date.

<form action="/posts/post-x-link/comments" method="post">
  <input type="hidden" name="authenticity_token" value="zzcjgpp55...+yxjDy4LmydrMVqsAfQ/+igqKDcIAg==">

Rails uses these authenticity_tokens to prevent CSRF attack. Skip this protection for comment :create method.

class CommentsController < ApplicationController
  protect_from_forgery except: :create
Rate Limit

And a rate limit is set for POST request of comment creation. It’s simply implemented on top of Redis.

def exceed_limit?
  key = request.remote_ip
  if EXISTS key
    return true # the ip has been submitted a comment lately
  else
    INCR key
    EXPIRE key, CREATION_RATE_LIMIT
    return false
  end
end

A more complex API rate limit can be implemented using “leaky bucket” algorithm.

This allows for infrequent bursts of calls, and allows your app to continue to make an unlimited amount of calls over time.

Shopify implements its API rate limit in that way.

The bucket size is 40 calls (which cannot be exceeded at any given time), with a “leak rate” of 2 calls per second that continually empties the bucket. If your app averages 2 calls per second, it will never trip a 429 error (“bucket overflow”).

Flash

When POST request is rejected due to rate limitation, a flash message is shown to alert the user, which is meant to be short-lived. At first implementation, the flash message was statically embedded into posts/show.html.erb.

<div class="flash-msgs screen-center">
  <% flash.each do |name, msg| %>
    <%= content_tag :div, msg, class: [name, "flash-msg", "fade-out", "bg-danger"] %>
  <% end %>
</div>

Unfortunately, it means that the flash message was sticked in the page cache (until another operation invalidates that cache). To fix this bug, POST request is implemented in AJAX way, so that flash messages can be embedded dynamically.

Every layer introduced into system adds more complexity into system at last🤔.