Avoid parsing Rails controller params by using Metal

Need more metal!

Hands by Incase is licensed under CC BY 2.0

I was looking at this controller today, which was using lots of memory:


class WebhooksController < ApplicationController
  def create
    if SomeModel.exists?(params[:model_id])
      ProcessJSONinSidekiq.perform_later(params.to_json)
    end
    render json: {}
  end
end

Most of the memory (and time) was coming from the fact that this was receiving a large amount of JSON, which gets converted to the params Hash (actually ActionController::Parameters) which we then convert back to JSON for a Sidekiq job.

We can do better.

First, I needed to move the SomeModel.exists? check into the job, which was pretty easy.

Next, I can send the raw JSON to the Sidekiq job using request.raw_post, rather than calling params.to_json :


class WebhooksController < ApplicationController
  def create
    ProcessJSONinSidekiq.perform_later(request.raw_post)
    render json: {}
  end
end

Rails will still automatically convert the JSON to the params Hash though, and that is still unnecessary for us.

I realized at this point we really should be using ActionController::API instead of ApplicationController because it is leaner and more efficient for API-related requests (no view rendering, etc.). That didn’t go far enough here though. I needed metal. 🤘🏻

ActionController::Metal is lower level than ActionController::API and removes pretty much everything. It does have a concept of params, but they aren’t loaded unless you use the method. I had to tweak my return a bit, but it was pretty simple. Now I never touch the JSON. I simply send it along.


class WebhooksController < ActionController::Metal
  def create
    ProcessJSONinSidekiq.perform_later(request.raw_post)
    [200, { "Content-Type" => "application/json" }, "{}"]
  end
end

Photo of Daniel Morrison

Daniel founded Collective Idea in 2005 to put a name to his growing and already full-time freelance work. He works hard writing code, teaching, and mentoring.

Comments

Add a Comment

Hmm...that didn't work.

Something went wrong while adding your comment. If you don't mind, please try submitting it again.

Comment Added!

Your comment has been added to this post. Please refresh this page to view it.

Optional. If added, we will display a link to the website in your comment.
Optional. Never shared or displayed in your comment.