Rails and Angular – camelCase or underscore?

When you’re writing your APIs in Rails, you may have an app for the front end, say, in Angular. You may send data between these two in the JSON format.

The coding conventions in both these technologies are exact opposites when it comes to names.

In rails you want your hash to look like

{
    id: 1,
    first_name: 'john doe'
}

In angular you want your object to look like

{
    id: 1,
    firstName: 'john doe'
}

In order to achieve this, without having to change the names manually before/after every data transfer request, you can add a parser in your initializer sequence:

config/initializers/json_param_key_transform.rb

ActionDispatch::Request.parameter_parsers[:json] = -> (raw_post) {
    data = ActiveSupport::JSON.decode(raw_post)
    data = {:_json => data} unless data.is_a?(Hash)
    data.deep_transform_keys!(&:underscore)
}

This will first decode raw data in the body of a request into a hash. It will then transform all the keys in the hash to convert camelCase into underscore. Your controllers’ actions will receive this modified hash as params.

Now, when you are sending data from your API to your Angular app, you want it to be camelized. We can achieve this by overriding the as_json method of your models.

If you have a base class for all your models, then you can do this in it. Otherwise, write a new abstract class which would be the base class for all your models.

model_base.rb

class ModelBase < ApplicationRecord
    self.abstract_class = true

    def as_json(options={})
        json = super(options)
        if json.is_a?(Array) then
                return_hash = [];
                json.each do |x|
                    return_hash << x.deep_transform_keys { |key| key.to_s.camelize(:lower)}
                end
                return return_hash
            else

                return json.deep_transform_keys { |key| key.to_s.camelize(:lower)}
            end
    return 
  end
end

Now in your model, when you say @some_instance.as_json, the resulting hash will be camelized instead of with underscores.

If you do not want to override the as_json method of your models, you can also write this method in your ApplicationController, and call it before rendering your JSON.

application_controller.rb

def underscore_to_camel(hash_obj)
    return_obj = nil;
    if hash_obj.is_a?(Array) then
        return_obj = [];
        hash_obj.each do |x|
            return_obj << x.deep_transform_keys { |key| key.to_s.camelize(:lower)}
        end
        return return_obj
    else
        return_obj = hash_obj.deep_transform_keys { |key| key.to_s.camelize(:lower)}
    end
end

some_controller.rb

render json: underscore_to_camel(@some_instance)

Now the JSON data received by your angular app will be camelized.

Credits for the initializer idea:
http://stackoverflow.com/a/30557924

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: