Today I Learned

This project exists to catalogue the sharing & accumulation of knowledge as it happens day-to-day. Posts have a 200-word limit, and posting is open to any Rocketeer as well as selected friends of JetRockets. We hope you enjoy learning along with us.

5 posts by Alexander Spitsyn

Handling IP addresses using PostgreSQL

PostgreSQL provides a inet and cidr datatypes for storing net addresses and proceed operations with them.

Host address and it’s subnet can be stored with inet, while cidr can contain only network address:

select inet '192.168.0.1/24';
      inet
----------------
 192.168.0.1/24
select cidr '192.168.0.0/24'; -- valid cidr
      cidr
----------------
 192.168.0.0/24
select cidr '192.168.0.1/24'; -- invalid: cidr must not be a host address
ERROR:  invalid cidr value: "192.168.0.1/24"
LINE 1: select cidr '192.168.0.1/24';
                    ^
DETAIL:  Value has bits set to right of mask.

In case there’s no number after slash in cidr address the netmask is to equal 32:

select cidr('127.0.0.1');
     cidr
--------------
 127.0.0.1/32

The value above represents a subnet address, while the same value passed to inet represents a host:

select inet('127.0.0.1');
   inet
-----------
 127.0.0.1

Checking inclusion or equality can be performed with >>= and <<= operators:

select inet '192.168.0.1/24' >>= inet '192.168.0.0'; -- returns true
select cidr '192.168.0.0/24' >>= inet '192.168.0.0/12'; -- returns false
select cidr '192.168.0.0' >>= cidr '192.168.0.0'; -- returns true

And getting a netmask by a net address can be performed with netmask:

select netmask(inet('192.168.0.0/24')); -- returns 255.255.255.0
select netmask(cidr('127.0.0.1')); -- returns 255.255.255.255

How to conditionally render template in Grape resources?

Suppose you need to conditionally render some template in a given endpoint of a Grape resource. There is a env data in Grape::API class that represents Rack environment of the request. env is just a simple Ruby hash and we can pass the template name to it’s api.tilt.template key to render that template:

env['api.tilt.template'] = 'foo/bar.json'

Then let’s define a render method in Base resourсe:

class Base < Grape::API
  def self.inherited(subclass)
    super

    subclass.instance_eval do
      helpers do
        def render(template_name)
          env['api.tilt.template'] = template_name
        end
      end
    end
  end
end

Now we can use it in the following way:

class ContactsResource < Base
  desc 'Create contact', http_codes: [[201, 'Created']]

  post '/contacts' do
    contact = Contact.new(params[:contact])

    if contact.save
      render 'v1/contacts/show.json'
    else
      error!({ errors: contact.errors.full_messages }, 422)
    end
  end
end

Getting rid of inefficient constantize

Trying to improve performance of one controller I’ve found the following:

def application_klass
  @application_klass ||= "application/#{params[:type]}".classify.constantize
end

There are Application::Rental and Application::Bridge models in our rails app, so the method above was used in two places:

  1. application_klass.to_s – to get the model name as a string
  2. application_klass.model_name.human – to get a class name without module prefix

I’ve refactored method in the following way:

def application_klass
  @application_klass ||= "application/#{params[:type]}".classify
end 

And it’s occurrences now looks like this:

  1. application_klass – just call this method to get a model name
  2. application_klass.demodulize – using demodulize to split a string with ::

I’ve got rid of unnecessary constantize method, which is quite inefficient: just imagine that your application tries to find a constant in your project with the name specified in the string. See the benchmarks below to evaluate performance gains:

counter = 100_000
type = 'Rental'

Benchmark.bm(30) do |x|
  x.report('demodulize: ')                   { counter.times { "application/#{type}".classify.demodulize } }
  x.report('constantize.model_name.human: ') { counter.times { "application/#{type}".classify.constantize.model_name.human } }
end

                                     user     system      total        real
demodulize:                      3.560000   0.760000   4.320000 (  4.381891)
constantize.model_name.human:    8.500000   0.070000   8.570000 (  8.601007)

How to implement inheritance in Grape resources?

Grape uses specific DSL to define endpoints in API, that’s why you can’t use base class’ instance methods in descendant resources. But there’s one trick:

There’s an #inherited class method in Ruby which is triggered every time some class inherits from ancestor class. It passes one argument - descendant class. Calling descendant’s #instance_eval method we can place any useful stuff inside a block: methods, helpers, before-do’s, etc, in this way evaluating it in context of subclass.

class Base < Grape::API
  def self.inherited(subclass)
    super

    subclass.instance_eval do
      helpers do
        def current_user
          @current_user ||= User.find(params[:user_id])
        end
      end
      # ...
    end 
  end
end

class DocumentsResource < Base
  post '/documents' do
    @document = current_user.documents.build
    # ...
  end
end

Note that it’s not real inheritance because Base class has not methods defined inside subclass#instance_eval block.