Wednesday, 6 May 2015

The benefit of the squeel gem over standard active record

The benefit of the squeel gem over the standard active record

Let's try this query:
Field.where(id: 10).unscope(where: :id)
It results in the below SQL:
"SELECT \"fields\".* FROM \"fields\"

Let try to unscope something a bit more difficult:
Field.where('id > 10').unscope(where: :id)
In this case the unscoping didn't work as we intended:
SELECT \"fields\".* FROM \"fields\" WHERE (id > 10)

Let's try now by using squeel gem:
Field.where{id > 10}.unscope(where: :id).to_sql
Now the unstopping works just as we intended:
"SELECT \"fields\".* FROM \"fields\""

Enjoy :)

Friday, 16 January 2015

Testing the ActiveRecord models using Rspec

Usually the skeleton of my models spec looks like this:

require 'spec_helper'
describe Car do
  context 'class hierarchy' do
    #Here comes the class hierarchy specification
  context 'fields' do
  context 'assotiations' do
    #Here comes the enumeration of associations
  context 'validations' do
    #Here comes the validation of models
  context 'callbacks' do
    #Specs for callbacks
  context 'methods' do

Testing the class hierarchy:
Since the model could include modules which affect the functionality I consider it necessary to assert on them.

describe Car do
  context 'class hierarchy' do
    specify {expect(subject.class).to be < ActiveRecord::Base}
    specify{expect(subject).to be_kind_of(Elasticsearch::Model)}
    specify{expect(subject).to be_kind_of(Elasticsearch::Model::Callbacks)}

Testing the fields:
I often encountered errors when the model was expected to have a field and that field was missing. So I always assert on the used fields:

describe Car do
  context 'fields' do
    specify {expect(subject).to respond_to(:name)}
    specify {expect(subject).to respond_to(:filter)}

Testing the associations:
I test the presence of the correct associations using the 'shoulda-matchers' gem.

describe Car do
  context 'assotiations' do
    specify { expect(subject).to belong_to(:user) }
    specify { expect(subject).to belong_to(:manufacturer) }

Testing the validations:
I usually test the validations of the fields using the 'shoulda-matchers' gem.

describe Car do
  context 'validations' do
    specify { expect(subject).to validate_uniqueness_of(:filter).scoped_to(:manufacturer_id)}

Testing the callbacks:
My callback test usually are like this:

describe Car do
  context 'validations' do
    context 'before_destroy' do
      specify 'call destroy like callback'do
        expect(equipment).to receive(:destroy_likes)

Testing the methods:
Usually I test the methods by calling it the asserting that all the necessary changes are made. I do this for all the execution paths.

Thursday, 15 January 2015

Api Development in Ruby On Rails

Recently I wrote a series of blog posts about the best practices of API development in RoR and how to develop API in general.

Let me summarize those posts:

Happy API development :)

API development in Rails error path

In my series of of API development I haven't covered the error handling.

Let me share my experience with you about what I have learned about proper error handling.
I call error path the case when the user can't achieve what he wants.

This case can happen by the following reasons:

  • The user calls an invalid url
  • The user addresses a missing resource
  • The user misses a mandatory parameter
  • The uses passes a wrong parameter
  • Some other internal error occurs
  • ...

Since thousands of calls can be made daily or hourly against the API there is no way to stop the server and debug it. So all the information related to the erroneous call must be recorded. Basically all the information to reproduce the error must be recorded. I call this ApiCallAudit.

Such an ApiCallAudit must contain:

  • All the incoming parameters
  • The type of call (GET, POST, DELETE, ...)
  • cookies
  • backtrace
  • created_at
I added some additional fields to it for filtering purposes:

  • level. It serves to quickly determine the possible source of errors. It could be parameter_error, unexpected_error, parameter_missing_error, entity_missing_error
  • status. It is a default error message.
  • code. An error code which uniquely identifies the error.
In the beginning the error code was missing from my design and the mobile clients were using the default error message. This has some disadvantages:
  • The mobile UI is usually developed in a different codebase. And the server side error message modification is not possible. Specially if the same chunk of server side code is serving many applications.
  • -The language used on the mobile UI can vary. For example the UX developer can decide to use:
    1. "You haven't provided the group" - First person complaining style.
    2. "The group is missing" - Passive objective style
    3. "Please provide a group" - Proactive gentle style
    4. "Select a group!" - Imperative style
    5. ...
In order to formulate the sentences which reflects the application mood the mobile developer needs to interpret the returned error based on its error_code and formulate its own corresponding message.

Happy coding :)