Caching in development environment in Rails 5

This blog is part of our Rails 5 series.

In Rails 4 if I’m doing work related to caching then first I need to turn caching “on” by opening file config/environments/development.rb and changing following line.

config.action_controller.perform_caching = false

After changing the value from false to true, I need to restart the server.

This means that if I am testing caching behavior locally then every time I turn caching “on” or “off” I need to restart the server.

New command to create development cache in Rails 5

Rails 5 has introduced a new command to create development cache and help us test how caching behaves in development mode. Here is the issue and here is the pull request.

$ rails dev:cache
Development mode is now being cached.

Execution of the above command creates file caching-dev.txt in tmp directory.

How does it work?

In Rails 5 when a brand new Rails app is created then config/environments/development.rb file will have the following snippet of code.

if Rails.root.join('tmp/caching-dev.txt').exist?
  config.action_controller.perform_caching = true
  config.static_cache_control = "public, max-age=172800"
  config.cache_store = :mem_cache_store
else
  config.action_controller.perform_caching = false
  config.cache_store = :null_store
end

In the above code we are checking if the file tmp/caching-dev.txt is present and then use :mem_cache_store to enable caching only if the file is found.

Also, here is a snippet from the dev cache source code.

def dev_cache
  if File.exist? 'tmp/caching-dev.txt'
    File.delete 'tmp/caching-dev.txt'
    puts 'Development mode is no longer being cached.'
  else
    FileUtils.touch 'tmp/caching-dev.txt'
    puts 'Development mode is now being cached.'
  end

  FileUtils.touch 'tmp/restart.txt'
end

What is the advantage

The advantage is that we do not need to restart the server manually if we want to turn caching “on” or “off”. It is internally taken care by the dev_cache method that is executed when rails dev:cache is executed. You can see in the source code that tmp/restart.txt is being touched.

Please note that this feature is not supported by unicorn, thin and webrick. My guess is that DHH wants this feature because his team uses pow and pow restarts when tmp/restart.txt is touched. He also created an issue for spring to watch tmp/restart.txt long time back.

Disabling development cache

Execute the same command that was used to enable caching. If caching was previously enabled then it will be turned “off” now.

$ rails dev:cache
Development mode is no longer being cached.

Configure PostgreSQL to allow remote connection

By default PostgreSQL is configured to be bound to “localhost”.

$ netstat -nlt
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:3737          0.0.0.0:*               LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN

As we can see above port 5432 is bound to 127.0.0.1. It means any attempt to connect to the postgresql server from outside the machine will be refused. We can try hitting the port 5432 by using telnet.

$ telnet 107.170.11.79 5432
Trying 107.170.11.79...
telnet: connect to address 107.170.11.79: Connection refused
telnet: Unable to connect to remote host

Configuring postgresql.conf

In order to fix this issue we need to find postgresql.conf. In different systems it is located at different place. I usually search for it.

$ find \ -name "postgresql.conf"
/var/lib/pgsql/9.4/data/postgresql.conf

Open postgresql.conf file and replace line

listen_addresses = 'localhost'

with

listen_addresses = '*'

Now restart postgresql server.

$ netstat -nlt
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:2812          0.0.0.0:*               LISTEN
tcp6       0      0 ::1:11211               :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 :::5432                 :::*                    LISTEN
tcp6       0      0 ::1:25                  :::*                    LISTEN

Here we can see that “Local Address” for port 5432 has changed to 0.0.0.0.

Configuring pg_hba.conf

Let’s try to connect to remote postgresql server using “psql”.

$ psql -h 107.170.158.89 -U postgres
psql: could not connect to server: Connection refused
	Is the server running on host "107.170.158.89" and accepting
	TCP/IP connections on port 5432?

In order to fix it, open pg_hba.conf and add following entry at the very end.

host    all             all              0.0.0.0/0                       md5
host    all             all              ::/0                            md5

The second entry is for IPv6 network.

Do not get confused by “md5” option mentioned above. All it means is that a password needs to be provided. If you want client to allow collection without providing any password then change “md5” to “trust” and that will allow connection unconditionally.

Restart postgresql server.

$ psql -h 107.170.158.89 -U postgres
Password for user postgres:
psql (9.4.1, server 9.4.5)
Type "help" for help.

postgres=# \l

You should be able to see list of databases.

Now we are able to connect to postgresql server remotely.

Please note that in the real world you should be using extra layer of security by using “iptables”.

Rails 5 brings consistency by wrapping all rake commands using rails

This blog is part of our Rails 5 series.

In Rails 4 some commands start with rails and some commands start with rake. This could be quite confusing for people new to Rails. Let’s see an example.

Our task is to write a database migration and then to run that migration.

rails g migration create_users

Above command creates a migration. Now we need to run that migration.

rake db:migrate

As you can see first command starts with rails and second command starts with rake.

In order to consolidate them we can either use rails for everything or we can use rake for everything.

Choosing rails command over rake command

Some favor using rake over rails. But an important feature missing in Rake is the ability to pass arguments.

rails console development

In order to execute the above command using rake we will have to pass console and development as arguments. We can pass these values using environment variables. That would mean adding additional code in Rake task to fetch right values and then only we will be able to invoke command rails console development.

Rails 5 enables executing rake commands with rails

Rails core team decided to have consistency by enabling rails command to support everything that rake does.

For example in Rails 5 commands like db:migrate, setup, test etc which are part of rake command in Rails 4 are now being supported by rails command. However you can still choose to use rake to run those commands similar to how they were run in Rails 4. This is because Rails community has introduced Rake Proxy instead of completely moving the command options from rake to rails.

What happens internally is that when rails db:migrate command is executed, Rails checks if db:migrate is something that rails natively supports or not. In this case db:migrate is not natively supported by rails, so Rails delegates the execution to Rake via Rake Proxy.

If you want to see all the commands that is supported by rails in Rails 5 then you can get a long list of options by executing rails --help.

Use app namespace for framework tasks in Rails 5

As rails command is now preferred over rake command, few rails namespaced framework tasks started looking little odd.

$ rails rails:update

$ rails rails:template

$ rails rails:templates:copy

$ rails rails:update:configs

$ rails rails:update:bin

So, Rails team decided to change the namespace for these tasks from rails to app.

$ rails app:update

$ rails app:template

$ rails app:templates:copy

$ rails app:update:configs

$ rails app:update:bin

Using rails rails:update will now give deprecation warning like: DEPRECATION WARNING: Running update with the rails: namespace is deprecated in favor of app: namespace. Run bin/rails app:update instead.

More improvements in pipeline

In Rails 4, the routes are usually searched like this.

$ rake routes | grep pattern

There is an effort underway to have a Rails command which might work as shown below.

$ rails routes -g pattern

There is also an effort to enable lookup for controller like this.

$ rails routes -c some_controller

Each form gets its own CSRF token in Rails 5

This blog is part of our Rails 5 series.

We have written an extensive blog on what CSRF is and what steps Rails 4 takes to prevent CSRF. We encourage you to read that blog to fully understand rest of this article.

Nested form can get around CSRF protection offered by Rails 4

A typical form generated in Rails 4 might look like this.

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="token_value">
</form>

Using code-injection, a Hacker can add another form tag above the form tag generated by Rails using JavaScript. Now the markup looks like this.

<form method="post" action="http://www.fraud.com/fraud">
  <form method= "post" action="/money_transfer">
    <input type="hidden" name="authenticity_token" value="token_value">
  </form>
</form>

HTML specification does not allow nested forms.

Since nested forms are not allowed browser will accept the top most level form. In this case that happens to be the form created by the hacker. When this form is submitted then “authenticity_token” is also submitted and Rails will do its check and will say everything is looking good and thus hacker will be able to hack the site.

Rails 5 fixes the issue by generating a custom token for a form

In Rails 5, CSRF token can be added for each form. Each CSRF token will be valid only for the method/action of the form it was included in.

You can add following line to your controller to add authenticity token specific to method and action in each form tag of the controller.

class UsersController < ApplicationController
  self.per_form_csrf_tokens = true
end

Adding that code to each controller feels burdensome. In that case you can enable this behavior for all controllers in the application by adding following line to an initializer.

# config/application.rb
Rails.configuration.action_controller.per_form_csrf_tokens = true

This will add authenticity token specific to method and action in each form tag of the application. After adding that token the generated form might look like as shown below.

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="money_transfer_post_action_token">
</form>

Authenticity token included here will be specific to action money_transfer and method post. Attacker can still grab authenticity_token here, but attack will be limited to money_transfer post action.

Rendering views outside of controllers in Rails 5

This blog is part of our Rails 5 series.

Rails request-response cycle is very easy to understand. A request hits the app, a route is matched to a controller action from routes.rb, and finally controller action processes the request and renders HTML or JSON based on the type of the request.

But sometimes we want to render our HTML or JSON response outside of this request-response cycle.

For example let’s say user is allowed to download PDF version of a report on web. This can be done using request-response cycle. We also need to send a weekly report to managers and the email should have the report as an attachment. Now we need to generate the same PDF but since emails are sent using background job the request-response cycle is missing.

Rails 5 has this feature baked in.

Let’s say we have a OrdersController and we want to render individual order outside of controller.

Fire up rails console and execute following command.

OrdersController.render :show, assigns: { order: Order.last }

This will render app/views/orders/show.html.erb with @order set to Order.last. Instance variables can be set using assigns in the same way we use them in controller actions. Those instance variables will be passed to the view that is going to be rendered.

Rendering partials is also possible.

OrdersController.render :_form, locals: { order: Order.last }

This will render app/views/orders/_form.html.erb and will pass order as local variable.

Say I want to render all orders, but in JSON format.

OrdersController.render json: Order.all
# => "[{"id":1, "name":"The Well-Grounded Rubyist", "author":"David A. Black"},
       {"id":2, "name":"Remote: Office not required", "author":"David & Jason"}]

Even rendering simple text is possible.

>> BooksController.render plain: 'this is awesome!'
  Rendered text template (0.0ms)
# => "this is awesome!"

Similar to text, we can also use render file and render template.

Request environment

A typical web request carries it’s own environment with it. We usually handle this environment using request.env in controllers. Certain gems like devise depends on env hash for information such as warden token.

So when we are rendering outside of controller, we need to make sure that the rendering happens with correct environment.

Rails provides a default rack environment for this purpose. The default options used can be accessed through renderer.defaults.

>> OrdersController.renderer.defaults
=> {:http_host=>"example.org", :https=>false, :method=>"get", :script_name=>"", :input=>""}

Internally, Rails will build a new Rack environment based on these options.

Customizing the environment

We can customize environment using method renderer. Let’s say that we need “method as post” and we want “https to be true” for our background job processing.

renderer = ApplicationController.renderer.new(method: 'post', https: true)
# => #<ActionController::Renderer:0x007fdf34453f10 @controller=ApplicationController, @defaults={:http_host=>"example.org", :https=>false, :method=>"get", :script_name=>"", :input=>""}, @env={"HTTP_HOST"=>"example.org", "HTTPS"=>"on", "REQUEST_METHOD"=>"POST", "SCRIPT_NAME"=>"", "rack.input"=>""}>

Now that we have our custom renderer we can use it to generate view.

renderer.render template: 'show', locals: { order: Order.last }

Overall this is a nice feature which enables reuse of existing code.

Not using https might be breaking file uploads

Recently we came across following error when mobile app was trying to upload images using backend API.

==> nginx-error.log <==

2015/12/16 07:34:13 [error] 1440#0: *1021901
sendfile() failed (32: Broken pipe) while sending request to upstream,
client: xxx.xx.xxx.xx, server: app-name.local,
request: "POST /api_endpoint HTTP/1.1",
upstream: "http://unix:/data/apps/app-name/shared/tmp/sockets/unicorn.sock:/api_endpoint",
host: "appname.com"

==> nginx-error.log <==

xxx.xx.xxx.xx - - [16/Dec/2015:07:34:13 - 0500]
"POST /api_endpoint HTTP/1.1" 502 1051 "-"
"Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13B143 (366691552)"

The backend API was developed using Ruby on Rails and was powered using NGINX HTTP server along with unicorn application server.

Notice the the http response received was 502 which is documented in RFC as shown below.

10.5.3 502 Bad Gateway The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request.

Debugging the problem

From the first look it seemed that the client_max_body_size parameter for nginx was too less, which might cause the request to fail if the uploaded filesize is greater than the allowed limit.

nginx.conf
http {
  ...
  client_max_body_size 250M;
  ...
}

But that was not the case with our NGINX configuration. The NGINX was configured to accept file size upto 250 megabytes, while the file being uploaded was around 6 megabytes.

In our Rails code we are forcing all traffic to use HTTPS by having production.rb to have following setting.

config.force_ssl = true

What this setting does is, it forces HTTPS by redirecting HTTP requests to their HTTPS counterparts. So any request accessing http://domain.com/path will be redirected to https://domain.com/path

Forcing all traffic to HTTPS still does not explain the vague error sendfile() failed (32: Broken pipe) while sending request to upstream and why the HTTP 502 error which means Bad Gateway

Here is how our nginx.conf is configured.

server {
  ...
  listen 80;
  listen 443 ssl;
  ...
}

NGINX is configured to accept both HTTP and HTTPS requests. This is a pretty standard setting so that application can support both HTTP and HTTPS. What it means is that nginx will accept both HTTP and HTTPS request. It would not force HTTP request to be HTTPS. It would forward HTTP request to rails backend api.

Here is what happens when you upload a file

When we upload a file then NGINX takes that request and passes that request to Rails. NGINX expects a response from Rails only when NGINX is done sending the whole request.

Let’s see what happens when a user visits login page using HTTP. NGINX takes the request and passes the request to Rails. When NGINX is done handing over the request to Rails then NGINX expects a response from Rails. However in this case rather than sending 200 Rails sends a redirect over HTTPS. So now NGINX takes up the request again over HTTPS and then hands over request to Rails. Rails processes the request and returns 200. Everything works out.

Now let’s see what happens when a file is uploaded over HTTP.

User uploads a file over HTTP. NGINX takes up the request and starts sending the file to Rails. More details about the file upload process can be see at RFC. The data is sent to server in chunks. When first chunk is sent to server then server notices that data is being sent over HTTP and it immediately sends a response that data should be sent over HTTPS.

In the meantime on the client side , client is still pushing rest of the data to the server. Client expects a response from the server only when it is done pushing all the data. However in this case server sends a response when client is not expecting it.

NGINX at this time is all confused and thinks something has gone wrong with the gateway and returns HTTP/1.1 502 Bad Gateway and aborts the upload operation. And that how we get the 502 error.

So next time you see an error like this make sure that you are using https to upload the file if server is enforcing https.

Year in review 2015

Year 2015 was an exciting year for BigBinary !

We added more clients. We increased our team size. We wrote more blogs, spoke at more conferences, and made even more videos !

Here is the breakdown.

We love conferences

We presented at 10 conferences across 7 countries, on topics from Rails to ReactJS.

We are all in ReactJS

We at BigBinary adopted ReactJS pretty early. Early in the year we published series of videos titled Learn ReactJS in steps which takes a “Hello World” app into a full TODO application using ReactJS in incremental steps.

Vipul and Prathamesh are currently authoring a book on ReactJS. Check it out at ReactJS by Example- Building Modern Web Applications with React Book

We also started an ios app using React Native. It’s coming along pretty good and soon we should see it in app store.

We authored many blogs

We love sharing our experiences via blogs on various topics like ReactJS, Rails, React Native and Robot framework etc. Here are some of our blogs from 2015.

Video Summary

Open Source

Apart from our team members contributing to various OpenSource projects, we also support some projects from our team. This year, we added and helped build following projects-

  • Wheel : Wheel is our Rails template for new Ruby on Rails projects, with sane defaults and setups for different environments, and common functionalities like image uploaders, debugging, etc.
  • Mail Interceptor : Interception, Forwarding emails in Ruby on Rails application
  • Handy : A collection handy tools and Rails tasks for your Project.
  • Learn ReactJS in Steps : Collection of examples from Learn ReactJS in step video series.
  • DoceboRuby : Ruby wrapper for Decobo LMS API
  • Doctsplit Chef : Check cookbox for docsplit ruby gem
  • Fixtures Dumper : Dump your Rails data to fixtures easily to a database to populate data.

Community Engagement

Along with speaking at various conferences, we also helped organize, our Fun edition of Pune’s regional RubyConf, DeccanRubyConf, and supported other Indian Conferences, including RubyConfIndia, GardenCity RubyConf.

We also help Pune’s local ruby meetup, which had a splendid engagement this year.

Overall we are super excited about what we accomplished in year 2015. We are looking forward to an exciting year of 2016!

Test runner in Rails 5

This blog is part of our Rails 5 series.

If you run bin/rails -h in a Rails 5 app, you will see a new command for running tests.

$ bin/rails -h
Usage: rails COMMAND [ARGS]

The most common rails commands are:
 generate    Generate new code (short-cut alias: "g")
 console     Start the Rails console (short-cut alias: "c")
 server      Start the Rails server (short-cut alias: "s")
 test        Run tests (short-cut alias: "t")

Before Rails 5, we had to use bin/rake test to run tests. But in Rails 5, we can use bin/rails test. It is not just replacement of old rake task but it is backed by a test runner inspired from RSpec, minitest-reporters, maxitest and others.

Let’s see what bin/rails test can do.

Running a single test

Now it is possible to run a single test out of the box using the line number of the test.

$ bin/rails test test/models/user_test.rb:27

Rails will intelligently run the test from user_test.rb having line number 27. Note that the line number 27 does not need to be first line of the test. Below is an example.

22: def test_valid_user
23:   hash = { email: 'bob@exmaple.com',
24:            first_name: 'John',
25:            last_name: 'Smith' }
26:
27:   user = User.new hash
28:
29:   assert user.valid?
30: end

In the above case, test_valid_user can be run as long as the line number provided is between 22 and 30.

Running multiple tests

You can also pass multiple test paths and Rails will run all of those tests.

$ bin/rails test test/models/user_test.rb:27 test/models/post_test.rb:42

It is also possible to run all tests from a directory.

$ bin/rails test test/controllers test/integration

Improved failure messages

When a test fails, Rails displays a command which can be used to just run the failed test.

$ bin/rails t
Run options: --seed 51858

# Running:

.F

Failure:
PostsControllerTest#test_should_get_new:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>


bin/rails test test/controllers/posts_controller_test.rb:15

I can simply copy bin/rails test test/controllers/posts_controller_test.rb:15 and rerun the failing test.

Failing fast

By default when a test fails then rails reports about the test failures and then moves on to the next test. If you want to stop running the test when a test fails then use option -f.

$ bin/rails t -f
Run options: -f --seed 59599

# Running:

..F

Failure:
PostsControllerTest#test_should_get_new:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>


bin/rails test test/controllers/posts_controller_test.rb:15

Interrupted. Exiting...


Finished in 0.179125s, 16.7481 runs/s, 22.3308 assertions/s.

3 runs, 4 assertions, 1 failures, 0 errors, 0 skips

Defer test output until the end of the full test run

By default when a test fails then rails prints F and then details about the failure like what assertion failed and how to re run the test etc.

If you want to have a clean output of . and F and would like all the test failures report to come at the every end then use option -d.

$ bin/rails t -d
Run options: -d --seed 29906

# Running:

..F...F

Finished in 0.201320s, 34.7704 runs/s, 49.6721 assertions/s.

  1) Failure:
PostsControllerTest#test_should_create_post [/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19]:
"Post.count" didn't change by 1.
Expected: 3
  Actual: 2


  2) Failure:
PostsControllerTest#test_should_get_new [/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:15]:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>

7 runs, 10 assertions, 2 failures, 0 errors, 0 skips

Failed tests:

bin/rails test test/controllers/posts_controller_test.rb:19
bin/rails test test/controllers/posts_controller_test.rb:15

Better backtrace output

By default when an error is encountered while running the test then the output does not contain full stacktrace. This makes debugging little bit difficult.

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007f86bc62b728>
    app/controllers/posts_controller.rb:29:in `create'
    test/controllers/posts_controller_test.rb:20:in `block (2 levels) in <class:PostsControllerTest>'
    test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest

Now we can use -b switch, which will display complete backtrace of error message.

$ bin/rails t -b

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007fc53c4eb868>
    /rails-5-test-runner-app/app/controllers/posts_controller.rb:29:in `create'
    /sources/rails/actionpack/lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
    /sources/rails/actionpack/lib/abstract_controller/base.rb:183:in `process_action'
    /sources/rails/actionpack/lib/action_controller/metal/rendering.rb:30:in `process_action'
    /sources/rails/actionpack/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
    /sources/rails/activesupport/lib/active_support/callbacks.rb:126:in `call'
.....
    /sources/rails/activesupport/lib/active_support/testing/assertions.rb:71:in `assert_difference'
    /rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest>'

Leveraging power of Minitest

The test runner also leverages power of minitest by providing some handy options.

Switch -s to provide your own seed

Now we can also provide our own seed using -s switch.

$ bin/rails t --s 42000

Switch -n to run matching tests

Switch -n will run tests matching the given string or regular expression pattern.

$ bin/rails t -n "/create/"
Run options: -n /create/ --seed 24558

# Running:

E

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007faa39c2df90>
    app/controllers/posts_controller.rb:29:in `create'
    test/controllers/posts_controller_test.rb:20:in `block (2 levels) in <class:PostsControllerTest>'
    test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest>'


bin/rails test test/controllers/posts_controller_test.rb:18

Finished in 0.073857s, 13.5396 runs/s, 0.0000 assertions/s.

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips

Verbose output

It is also possible to see the verbose output using -v switch. It shows time required to run each test. This would help in detecting slow running tests.

$ bin/rails t -v
Run options: -v --seed 30118

# Running:

PostsControllerTest#test_should_destroy_post = 0.07 s = .
PostsControllerTest#test_should_update_post = 0.01 s = .
PostsControllerTest#test_should_show_post = 0.10 s = .
PostsControllerTest#test_should_create_post = 0.00 s = F

Failure:
PostsControllerTest#test_should_create_post:
"Post.count" didn't change by 1.
Expected: 3
  Actual: 2

bin/rails test test/controllers/posts_controller_test.rb:19

PostsControllerTest#test_should_get_new = 0.02 s = .
PostsControllerTest#test_should_get_index = 0.01 s = .
PostsControllerTest#test_should_get_edit = 0.00 s = .

Finished in 0.210071s, 33.3220 runs/s, 47.6028 assertions/s.

7 runs, 10 assertions, 1 failures, 0 errors, 0 skips

Colored output

Now by default we will get colored output. No need to add additional gem to colored output.

colored test output

With all these awesome features, testing Rails 5 apps has definitely become a better experience. Rails has shipped all these features within the framework itself so you don’t have to use multiple gems and libraries to achieve all of these things.

ApplicationRecord in Rails 5

This blog is part of our Rails 5 series.

Rails 5 beta-1 was recently released and one of the notable change was introduction of ApplicationRecord.

Upto Rails 4.2, all models inherited from ActiveRecord::Base. But starting from Rails 5, all models will inherit from ApplicationRecord.

class Post < ApplicationRecord
end

What happened to ActiveRecord::Base ?

Well not much changed in reality. Following file will be automatically added to models in Rails 5 applications.

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

This behavior is similar to how controllers inherit from ApplicationController instead of inheriting from ActionController::Base.

Now ApplicationRecord will be a single point of entry for all the customizations and extensions needed for an application, instead of monkey patching ActiveRecord::Base.

Say I want to add some extra functionality to Active Record. This is what I would do in Rails 4.2.

module MyAwesomeFeature
  def do_something_great
    puts "Doing something complex stuff!!"
  end
end

ActiveRecord::Base.include(MyAwesomeFeature)

But now, ActiveRecord::Base forever includes MyAwesomeFeature and any class inheriting from it also includes MyAwesomeFeature even if they don’t want it.

This is especially true if you are using plugins and engines where monkey patching to ActiveRecord::Base can leak into engine or plugin code.

But with ApplicationRecord, they will be localized to only those models which are inheriting from ApplicationRecord, effectively only to your application.

class ApplicationRecord < ActiveRecord::Base
  include MyAwesomeFeature

  self.abstract_class = true
end

Migrating from Rails 4

By default all new Rails 5 applications will have application_record.rb. If you are migrating from Rails 4, then simply create app/models/application_record.rb as shown below and change all models to inherit from ApplicationRecord instead of ActiveRecord::Base.

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

Explicitly ssh into vagrant machine

After building vagrant machine the command to ssh into the guest machine is pretty simple.

vagarnt ssh

While working with chef I needed to explicitly ssh into the vagrant machine. It took me sometime to figure it out.

The key is command vagrant ssh-config. The output might look like this.

$ vagrant ssh-config
Host vmachine
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/nsingh/code/vagrant-machine/.vagrant/machines/vmachine/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL
  ForwardAgent yes

Open ~/.ssh/config and paste the output at the end of the file and save the file.

Now I can ssh into vagrant machine using ssh command as shown below.

ssh vmachine

If you are wondering from where the name vmachine came then this is the name I had given to my vagrant machine .

How constant lookup and resolution works in Ruby on Rails

When a Rails application involving multiple gems, engines etc. are built then it’s important to know how constants are looked up and resolved.

Consider a brand new Rails app with model User.

class User
  def self.model_method
    'I am in models directory'
  end
end

Run User.model_method in rails console. It runs as expected.

Now add file user.rb in lib directory.

class User
  def self.lib_method
    'I am in lib directory'
  end
end

Reload rails console and try executing User.model_method and User.lib_method. You will notice that User.model_method gets executed and User.lib_method doesn’t. Why is that?

In Rails we do not import files

If you have worked in other programming languages like Python or Java then in your file you must have statements to import other files. The code might look like this.

import static com.googlecode.javacv.jna.highgui.cvCreateCameraCapture;
import static com.googlecode.javacv.jna.highgui.cvGrabFrame;
import static com.googlecode.javacv.jna.highgui.cvReleaseCapture;

In Rails we do not do that. That’s because DHH does not like the idea of opening a file and seeing the top of the file littered with import statements. He likes to see his files beautiful.

Since we do not import file then how does it work?

In Rails console when user types User then rails detects that User constant is not loaded yet. So it needs to load User constant. However in order to do that it has to load a file. What should be the name of the file. Here is what Rails does. Since the constant name is User Rails says that I’m going to look for file user.rb.

So now we know that we are looking for user.rb file. But the question is where to look for that file. Rails has autoload_path. As the name suggests this is a list of paths from where files are automatically loaded. Rails will search for user.rb in this list of directories.

Open Rails console and give it a try.

$ rails console
Loading development environment (Rails 4.2.1)
irb(main):001:0> ActiveSupport::Dependencies.autoload_paths
=> ["/Users/nsingh/code/bigbinary-projects/wheel/app/assets",
"/Users/nsingh/code/bigbinary-projects/wheel/app/controllers",
"/Users/nsingh/code/bigbinary-projects/wheel/app/models",
"/Users/nsingh/code/bigbinary-projects/wheel/app/helpers"
.............

As you can see in the result one of the folders is app/models. When Rails looks for file user.rb in app/models then Rails will find it and it will load that file.

That’s how Rails loads User in Rails console.

Adding lib to the autoload path

Let’s try to load User from lib directory. Open config/application.rb and add following code in the initialization part.

config.autoload_paths += ["#{Rails.root}/lib"]

Now exit rails console and restart it. And now lets try to execute the same command.

$ rails console
Loading development environment (Rails 4.2.1)
irb(main):001:0> ActiveSupport::Dependencies.autoload_paths
=> ["/Users/nsingh/code/bigbinary-projects/wheel/app/lib",
"/Users/nsingh/code/bigbinary-projects/wheel/app/assets",
"/Users/nsingh/code/bigbinary-projects/wheel/app/controllers",
"/Users/nsingh/code/bigbinary-projects/wheel/app/models",
"/Users/nsingh/code/bigbinary-projects/wheel/app/helpers"
.............

Here you can see that lib directory has been added at the very top. Rails goes from top to bottom while looking for user.rb file. In this case Rails will find user.rb in lib and Rails will stop looking for user.rb. So the end result is that user.rb in app/models directory would not even get loaded as if it never existed.

Enhancing a model

Here we are trying to add an extra method to User model. If we stick our file in lib then our user.rb is never loaded because Rails will never look for anything in lib by default. If we ask Rails to look in lib then Rails will not load file from app/models because the file is already loaded. So how do we enhance a model without sticking code in app/models/user.rb file.

Introducing initializer to load files from model and lib directories

We need some way to load User from both models and lib directories. This can be done by adding an initializer to config/initializers directory with following code snippet

%w(app/models lib).each do |directory|
  Dir.glob("#{Rails.root}/#{directory}/user.rb").each {|file| load file}
end

Now both User.model_method and User.lib_method get executed as expected.

In the above case when first time user.rb is loaded then constant User gets defined. Second time ruby understands that constant is already defined so it does not bother defining it again. However it adds additional method lib_method to the constant.

In that above case if we replace load file with require file then User.lib_method will not work. That is because require will not load a file if a constant is already defined. Read here and here to learn about how load and require differ.

Using ‘require_relative’ in model

Another approach of solving this issue is by using require_relative inside model. require_relative loads the file present in the path that is relative to the file where the statement is called in. The desired file to be loaded is given as an argument to require_relative

In our example, to have User.lib_method successfully executed, we need to load the lib/user.rb. Adding the following code in the beginning of the model file user.rb should solve the problem. This is how app/models/user.rb will now look like.

require_relative '../../lib/user'

class User
  def self.model_method
    'I am in models directory'
  end
end

Here require_relative upon getting executed will first initialize the constant User from lib directory. What follows next is opening of the same class User that has been initialized already and addition of model_method to it.

Handling priorities between Engine and App

In one of the projects we are using engines. SaleEngine has a model Sale. However Sale doesn’t get resolved as path for engine is neither present in config.autoload_paths nor in ActiveSupport::Dependencies.autoload_paths. The initialization of engine happens in engine.rb file present inside lib directory of the engine. Let’s add a line to load engine.rb inside application.rb file.

require_relative "../sale_engine/lib/sale_engine/engine.rb"

In Rails console if we try to see autoload path then we will see that lib/sale_engine is present there. That means we can now use SaleEngine::Engine.

Now any file we add in sale_engine directory would be loaded. However if we add user.rb here then the user.rb mentioned in app/models would be loaded first because the application directories have precedence. The precedence order can be changed by following statements.

engines = [SaleEngine::Engine] # in case there are multiple engines
config.railties_order = engines + [:main_app]

The symbol :main_app refers to the application where the server comes up. After adding the above code, you will see that the output of ActiveSupport::Dependencies now shows the directories of engines first (in the order in which they have been given) and then those of the application. Hence for any class which is common between your app and engine, the one from engine will now start getting resolved. You can experiment by adding multiple engines and changing the railties_order.

Further reading

Loading of constants is a big topic and Xavier Noria from Rails core team has made some excellent presentations. Here are some of them

We have also made a video on How autoloading works in Rails.

Using Stripe API in React Native with fetch

Stripe makes it easy to accept payments online. Stripe offers an npm package with nice documentation.

Problem with using Stripe in React Native

I added stripe to my React Native application using following command.

npm install stripe --save

Added Stripe to the project as shown below.

var stripe = require('stripe')('stripe API key');

And now I’m getting following error.

could not mount

This’s because npm package uses stripe.js and stripe.js needs http provided by Node.JS.

Our React Native code does not actually run on Node.JS. I know while building React Native we use NPM and we have a node server running in the background so it feels like we are in Node.JS land and we can use everything Node.JS has to offer. But that’s not true. React Native code can’t depend on Node.JS because Node.JS is not shipped with ios. It means we can’t use any of Node.JS packages including http. It means we can’t use stripe npm module.

Now you can remove require('stripe') line that was added in the last step.

Solution

React Native comes with Fetch api. From the documentation

The Fetch API provides a JavaScript interface for accessing an manipulating parts of the HTTP pipeline, such as requests and responses. It also provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network.

stripe.js is a nice wrapper around stripe api. stripe api is very well documented and is easy to use. Since we can’t use stripe.js we will use stripe api.

We will use fetch to create a credit card token using api.

return fetch('https://api.stripe.com/v1/tokens', {
  method: 'post',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Bearer ' + '<YOUR-STRIPE-API-KEY>'
  },
  body: formBody
});

Here, the header has 3 keys. Lets go through them one-by-one:

  • 'Accept': 'application/json' : Designates the content to be in JSON format.
  • 'Content-Type': 'application/x-www-form-urlencoded' : This tells the endpoint that the payload will be one giant query string where name and value pairs will be separated by the ampersand.
  • 'Authorization': 'Bearer ' + '<YOUR-STRIPE-API-KEY>' : This key is to authorize our actions on Stripe. Here Bearer is just a prefix which we need to attach to the api-key because Stripe uses OAuth 2.0 . You can read more on the Bearer token usage here .

Payload needs to contain credit card details.

var cardDetails = {
  "card[number]": '1111 2222 3333 4444',
  "card[exp_month]": '01',
  "card[exp_year]": '2020',
  "card[cvc]": '123'
};

Since the Content-Type is application/x-www-form-urlencoded, the payload should be one query string. An example of this would be: city=Miami&state=Florida

Let’s prepare a proper payload.

var formBody = [];
for (var property in cardDetails) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(cardDetails[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

That’s it. Now we can attach formBody to the body part of the fetch request and we are good to go.

Final solution

Here’s the whole code snippet.

"use strict";

var stripe_url = 'https://api.stripe.com/v1/'
var secret_key = '<YOUR-STRIPE-API-KEY>'

module.exports.createCardToken = function (cardNumber, expMonth, expYear, cvc) {
  var cardDetails = {
    "card[number]": cardNumber,
    "card[exp_month]": expMonth,
    "card[exp_year]": expYear,
    "card[cvc]": cvc
  };

  var formBody = [];
  for (var property in cardDetails) {
    var encodedKey = encodeURIComponent(property);
    var encodedValue = encodeURIComponent(cardDetails[property]);
    formBody.push(encodedKey + "=" + encodedValue);
  }
  formBody = formBody.join("&");

  return fetch(stripe_url + 'tokens', {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': 'Bearer ' + secret_key
    },
    body: formBody
  });
};

This is an example of registering a credit card with stripe and getting the token. Similar implementations can be done for other API endpoints.

Rails 5 allows setting custom HTTP Headers for assets

This blog is part of our Rails 5 series.

Let’s look at by default what kind of response headers we get when we start with a brand new Rails 4.2.4 application.

header

Now let’s say that I want to set a custom response header. That’s easy. All I need to do is add following line of code in the controller.

response.headers['X-Tracking-ID'] = '123456'

Now I see this custom response header.

header

Setting custom response header for assets

Let’s say that I need that custom response header not only for standard web requests but also for my assets. For example application.js file is served by Rails in localhost. How would I set custom header to the asset being served by Rails here.

Actually that’s not possible in Rails 4. In Rails 4 we can set only one response header for assets that are served by Rails and that response header is Cache-Control.

Here is how I can configure Cache-Control for assets.

# open config/environments/production.rb and add following line
config.static_cache_control = 'public, max-age=1000'

Now we have modified ‘Cache-Control` header for the assets.

header

Besides Cache-Control no other response header can be set for assets served by Rails. That’s a limitation.

How Rails Apps lived with this limitation so far

Rails is not the best server to serve static assets. Apace and NGINX are much better at this job. Hence ,in reality, in production almost everyone puts either Apache or NGINX in front of a Rails server and in this way Rails does not have to serve static files.

Havig said that, Rails applications hosted at Heroku is an exception. Assets for Rails applications running at Heroku are served by Rails application itself.

Problem we ran into

Our website is hosted at heroku. When we ran Google page speed insights for our website we were warned that we were not using Expires header for the assets.

PageSpeed Insights Warning

Here are how the header looked for application.js.

PageSpeed Insights Warning

Now you see the problem we are running into.

  • Our application is hosted at Heroku.
  • Heroku lets Rails serve the assets.
  • Google page speed insights wants us to set Expires header to the assets.
  • Rails application allows only one header for the assets and that is ‘Cache-Control`.

One easy solution is to host our website at Digital Ocean and then use Apache or NGINX.

Rails 5 saves the day

Recently Rails merged basic support for access control headers and added ability to define custom HTTP Headers on assets served by Rails.

Behind the scenes, Rails uses ActionDispatch::Static middleware to take care of serving assets. For example, a request to fetch an image, goes through ActionDispatch::Static in the request cycle. ActionDispatch::Static takes care of serving Rack::File object from server with appropriate headers set in the response. The served image can have headers like Content-Type, Cache-Control.

Start using Rails master

To fix this, we first pointed the App to use Rails master.

gem 'rails', github: 'rails/rails'
gem 'rack', github: 'rack/rack' # Rails depends on Rack 2
gem 'arel', github: 'rails/arel' # Rails master works alongside of arel master.

Next, we changed asset configuration to start providing and using missing header for Expires.

# production.rb

config.public_file_server.headers = {
  'Cache-Control' => 'public, s-maxage=31536000, maxage=15552000',
  'Expires' => "#{1.year.from_now.to_formatted_s(:rfc822)}"
}

Here, we are first setting the Cache-Control header to use public (intermediate) caching, for a year (31536000 seconds) with maxage and s-maxage. Here s-maxage stands for Surrogate cache, which is used to cache internally by Fastly.

We then provide the missing Expires value with some future date in Internet formatted time value.

With this setup, we can see PageSpeed pickups the new headers on assets and does not warn us for the missing header.

PageSpeed Insights Warning

Here is the changed response header for asset.

PageSpeed Insights Warning

Further Reading

For better use and more details about different headers to use for the assets, please refer to RFC 2616.

Getting around Apple iTunesConnect account activation issue

It’s now 5 days since I talked to Apple support team and showed to them problem I was facing with activating my iTunesConnect account. So far I have not received any response from Apple.

And it’s not just me. A lot more people are facing the issue.

I’m sure one day Apple will fix this issue. In the meantime I’m posting how I got around this problem.

Migrating rails app from postgresql to sql server

We started development on a project with PostgreSQL as our database. However midway we had to switch to SQL Server for a variety of reasons.

Here are some of the issues we noticed while migrating to SQL Server.

Unique constraint on a column which has multiple NULL values

As per the ANSI SQL standard unique constraint should allow multiple NULL values.

PostgreSQL documentation on unique constraint states following.

In general, a unique constraint is violated when there is more than one row in
the table where the values of all of the columns included in the constraint are
equal.

However, two null values are not considered equal in this comparison.

That means even in the presence of a unique constraint it is possible to store
duplicate rows that contain a null value in at least one of the constrained
columns.

This behavior conforms to the SQL standard, but we have heard that
other SQL databases might not follow this rule. So be careful when developing
applications that are intended to be portable.

In SQL Server a unique constraint does not allow multiple NULL values.

Devise by default adds unique index on reset_password_token column.

add_index :users, :reset_password_token, :unique => true

Devise is doing the right thing by enforcing a unique index on reset_password_token so that when a user clicks on a link to reset password the application would know who the user is.

However here is the problem. If we add a new user then by default the value of reset_password_token is NULL. If we add another user then we have two records with NULL value in reset_password_token. This works in PostgreSQL.

But SQL Server would not allow to have two records with NULL in reset_password_token column.

So how do we solve this problem.

Partial index to rescue. It is also known as Filtered index. Both PostgreSQL and SQL server support it. Rails also supports partial index by allowing us to pass where option as shown below.

add_index :users, :reset_password_token,
                  unique: true,
                  where: 'reset_password_token IS NOT NULL'

Please visit this issue if you want to see detailed discussion on this topic.

This behavior of SQL Server comes in play in various forms. Let’s say that we are adding api_auth_token to an existing users table.

Typically a migration for that might look like as shown below.

add_column :users, :api_auth_token, :string,
                                    :null => true,
                                    :unique => true

In this case we have plenty of records in the users table so the above migration will fail in PostgreSQL. We will have to resort to usage of partial index to fix this issue.

Adding not null constraint on a column with an index

In PostgreSQL following case will work just fine.

add_column :users, :email, :string, :unique => true
change_column :users, :email, :null => false

Above migration will fail with SQL Server.

In SQL Server a “not null constraint” cannot be added on a column which has a index on it. We need to first remove the unique index, then add the “not null” constraint and then add the unique index back.

The other solution is to add not NULL constraint first in the migration and then add any index.

Serialize array into a string column

ActiveRecord supports Array Datatype for PostgreSQL. We were using this feature to store a list of IDs.

After switching to SQL server we converted the column into string type and serialized the array.

serialize :user_ids, Array

Configuring Pycharm IDE to run a Robot Framework test suite or a single test script

Pycharm is a convenient IDE to work with Robot framework. To run a test suite or a test script, one can do so only through console. Running tests through console is very demanding. If user can run tests from Pycharm itself then that helps improve productivity. This blog explains how to configure Pycharm to be able to run test suite or a single test from the IDE itself.

Configuration to run a single test script

pycharm robot 1 pycharm robot 2 pycharm robot 3

Running a single test script

pycharm robot 4

Configuration to run a particular test suite

pycharm robot 5

Running a particular test suite

pycharm robot 6

Optimize JavaScript code using BabelJS

Though Babel is a transpiler to convert ESNext code to ES5, it can be used to optimize the code as well.

Let’s say we want to convert following ES6 code using Babel.

let a = 10;
let b = 42;

if (a < b) {
  console.log("a is less than b");
} else {
  console.log("b is less than a");
}

It will get translated to:

"use strict";

var a = 10;
var b = 42;

if (a < b) {
  console.log("a is less than b");
} else {
  console.log("b is less than a");
}

All good so far. Let’s try Babel’s constant folding plugin. I am compiling the ES6 code from command line this time.

babel --plugins constant-folding index.js --out-file bundle.js -w

This gives us following output:

"use strict";

var a = 10;
var b = 42;

if (true) {
  console.log("a is less than b");
} else {
  console.log("b is less than a");
}

If condition changed from (a < b) to (true). The constant-folding plugin has smartly evaluated the conditional expression a < b and replaced the code with the result of that expression.

This plugin can also optimize other expressions as shown below.

// Unary operators
console.log(!true);

// Binary expression
console.log(20 + 22);

// Function calls
console.log(Math.min(91, 2 + 20));

Which gets optimized to:

// Unary operators
console.log(false);

// Binary expression
console.log(42);

// Function calls
console.log(22);

How does this actually work?

Though we are using a “constant folding plugin” to achieve this optimization, the real work happens in Babel itself.

For every expression in the code, the constant folding plugin calls evaluate function from Babel source code. This function checks whether it can confidently find end value for a given expression.

The evaluate function returns confidence level and end value for any given expression. Based on this “confidence level”, constant folding plugin replaces the expression with their end values altering our original code as follows.

How evaluate handles different cases

For code Math.min(10, 20), evaluate will return

{ confident: true, value: 10 }

For code a < b, evaluate will return

{ confident: true, value: true }.

But for user defined function like foo('bar') or browser defined console.log('hello'), evaluate will return

{ confident: false, value: undefined }.

In the above case “confident” value will be “false” even if function returns a constant value. For example for code foo(100), evaluate will return

{ confident: false, value: undefined }.

In the above case function foo will always return 100. Still Babel has low confidence level. Why? That’s because Babel sees that it is a function and it bails out. It does not even look inside to try to figure things out.

Here is evaluate code in Babel. You should check it out.

How much optimization is possible?

How much help we will get from Babel for optimizing our code? Will it optimize everything?

The answer is unfortunately no.

As of now, Babel optimizes logical, binary, conditional expressions. It can also evaluate function calls on literals like "babel".length confidently if the literal is string or number.

For function calls, it supports only certain callees like String, Number and Math. So call to a user defined function, even if it’s returning a fixed value, will not be optimized.

Experimental feature

This feature looks great. But it’s available as experimental feature. If you use the plugin you will get following warning. unless you enable experimental flag.

$ babel --plugins constant-folding index.js --out-file bundle.js -w

[BABEL] index.js: THE TRANSFORMER constant-folding HAS BEEN MARKED AS EXPERIMENTAL AND IS WIP. USE AT YOUR OWN RISK. THIS WILL HIGHLY LIKELY BREAK YOUR CODE SO USE WITH **EXTREME** CAUTION. ENABLE THE `experimental` OPTION TO IGNORE THIS WARNING.

In order to get rid of warning you need to pass --experimental flag like this.

$ babel --plugins constant-folding index.js --out-file bundle.js -w
--experimental

Eliminating dead code

In above code example, we know that the result of if (a < b) is true based on values of a and b. Since the result is not going to change no matter what there is no need to have the if and else clauses.

That’s dead code.

Can Babel help us eliminate dead code?

Yes with the help of minification.deadCodeElimination option.

babel --optional minification.deadCodeElimination index.js --out-file bundle.js -w

Which converts earlier code to:

"use strict";

console.log("a is less than b");

I will talk about how Babel can eliminate dead code in a later post.

How to test React Native App on a real iPhone

I have been developing a new iOS app using React Native. I have been testing it using simulator provided by Xcode. Now it’s time to test the app using a real device. One could ask why test on a real device if it works perfectly on a simulator. Here are some of the reasons.

  • There are a number of device specific features which are not testable on a simulator. Phone calls, camera, gps data, compass and vibration are a few of them.
  • Testing unexpected cases that can only be tested on a real device. Like how your application handles incoming calls, low memory situations, low disk space, limited data connectivity etc.
  • Hardware-wise, your device is different than your Mac. If your app is graphics intensive and requires a lot of CPU usage, it might work seamlessly on your simulator depending on your Mac’s specifications. But it might be laggy and glitchy on the real device.

Now let’s look into how you can start testing your React Native app on an real iPhone.

Step 1 - Plug in your device

Plug in your device to your Mac and open Xcode. You will be able to select your device to the right of the Play and Stop buttons.

select device

You might run into one of the following two errors if you have not enrolled into Apple’s Developer Program.

Error 1 : Failed to code sign

xcode error 1

xcode error 2

To fix above issues please enroll in Apple Developer program.

Error 2 : Disk Image could not be mounted

The Developer Disk Image could not be mounted :
You may be running a version of iOS that is not supported by this version of XCode

could not mount

This can happen if your iOS version is not supported by your current version of Xcode. To fix this, just update your Xcode to the latest version from the App Store.

Step 2 - Set right deployment target

In your Xcode project setup the Deployment Target should be set to less than or equal to the iOS version installed on the device.

If your iPhone is running iOS 7.0 and you have set “Deployment Target” as 8.0 then the app will not work. If your iPhone is running iOS 8.0 and you have set “Deployment Target” as 7.0 then the app will work.

deployment target

Step 3 - Fix “Could not connect to development server” error

So the app is installed and you can see the launch screen. That’s great. But soon you might get following error on your iPhone.

Could not connect to development server.
Ensure node server is running and available on the same
network – run ‘npm start’ from react-native root.

<img src=”/assets/testing_ios_app/connection-error-cf34a1f8eb8059baa422955e6a5c8361da648cf7564c657d469515eeb5e9b6f2.PNG” alt=”connection error” width=200 height=350 width=”640” height=”1136”>

To fix this open AppDelegate.m file in your project’s iOS folder.

Locate line mentioned below and replace localhost with your Mac IP address e.g. 192.168.x.x.

To find the ip address of your Mac this is what ReactNative suggests us to do.

you can get ip by typing ifconfig into the terminal and selecting the * inet value under en0:.

jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"];

Save and click run again. This will fix the error.

Step 3 - Fix connecting to API hosted on local development server

Now the app is installed and you can navigate through the app screens. If the app attempts to make API call to the server running locally on the machine then depending on how the local server was started it could be a problem.

In my case, I have a Ruby on Rails application running on my local machine. I had started my rails server by executing command rails server.

To do this, the app should be able to access the rails server using the private ip of the server e.g. 192.168.x.x:3000. Turned out that I had started my rails server using command rails server.

Becase of change in Rails 4.2 rails server listens to localhost and not 0.0.0.0.

The rails guide further says following.

with this change you will no longer be able to access the Rails server from a different machine, for example if your development environment is in a virtual machine and you would like to access it from the host machine. In such cases, please start the server with rails server -b 0.0.0.0 to restore the old behavior.

In this case iPhone is trying to talk to Rails server so Rails server must be started using following command.

rails server -b 0.0.0.0
or
rails server --binding=0.0.0.0

By doing so, now you can connect to your Rails app from your local network, by browsing to http://192.168.x.x:3000.

Summary

These were some of the issues I came across while testing my iOS app on an actual device and how I fixed them. Hopefully, this blog post helps you fix these error cases get you started on testing quickly.

Using ReactJS with Rails Action Cable

Recent DHH, announced availability of alpha version of Action Cable.

Action Cable is still under heavy development but it comes with examples to demonstrate its usage.

Action Cable integrates websocket based real-time communication in Ruby on Rails applications. It allows building realtime applications like Chats, Status updates, etc.

Action Cable + React

Action Cable provides real time communication. ReactJS is a good tool to manage view complexity on the client side. Together they make it easy to develop snappy web applications which requires state management on the client side without too much work.

Anytime data changes the new data is instantly provided by Action Cable and the new data is shown on the view without user doing anything on the application by ReactJS.

Integrating React

The official Action Cable Example is a chat application. We will be building the same application using ReactJS.

First follow the instructions mentioned to get a working chat application using Action Cable.

Now that the chat application is working let’s get started with adding ReactJS to the application.

Please note that we have also posted a number of videos on learning ReactJS. Check them out if you are interested.

Step 1 - Add required gems to Gemfile

# react-rails isn't compatible yet with latest Sprockets.
# https://github.com/reactjs/react-rails/pull/322
gem 'react-rails', github: 'vipulnsward/react-rails', branch: 'sprockets-3-compat'

# Add support to use es6 based on top of babel, instead of using coffeescript
gem 'sprockets-es6'

Step 2 - Add required JavaScript files

Follow react-rails installation and run rails g react:install.

This will

  • create a components.js file.
  • create app/assets/javascripts/components/ directory.

Now put following lines in your application.js:

//= require react
//= require react_ujs
//= require components

Make sure your app/assets/javascripts/application.js looks like this

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require react
//= require react_ujs
//= require components
//= require cable

//= require channels
//= require_tree .

Step 3 - Setup Action Cable to start listening to events

We will be using es6, so lets replace the file app/assets/javascripts/channels/index.coffee, with app/assets/javascripts/channels/index.es6 and add following code.

var App = {};
App.cable = Cable.createConsumer('ws://localhost:28080');

Also remove file app/assets/javascripts/channels/comments.coffee, which is used to setup subscription. We will be doing this setup from our React Component.

Step 4 - Create CommentList React Component

Add following code to app/assets/javascripts/components/comments_list.js.jsx.

var CommentList = React.createClass({
  getInitialState(){
    let message = JSON.parse(this.props.message);
    return {message: message};
  },

  render() {
    let comments = this.state.message.comments.map((comment) => {
      return this.renderComment(comment);
    });

    return (
      <div>{comments}</div>
    );
  },

  renderComment(comment) {
    return (
      <article key={comment.id}>
        <h3>Comment by { comment.user.name }</h3>
        <p>{ comment.content }</p>
      </article>
    );
  }
});

Here we have defined a simple component to display a list of comments associated with a message. Message and associated comments are passed as props.

Step 5 - Create message JSON builder

Next we need to setup data needed to be passed to the component.

Add following code to app/views/messages/_message.json.jbuilder.

json.(message, :created_at, :updated_at, :title, :content, :id)
json.comments(message.comments) do |comment|
  json.extract! comment, :id, :content
  json.user do
    json.extract! comment.user, :id, :name
  end
end

This would push JSON data to our CommentList component.

Step 6 - Create Rails Views to display component

We now need to setup our views for Message and display of Comments.

We need form to create new Comments on messages. This already exists in app/views/comments/_new.html.erb and we will use it as is.

<%= form_for [ message, Comment.new ], remote: true do |form| %>
  <%= form.text_area :content, size: '100x20' %><br>
  <%= form.submit 'Post comment' %>
<% end %>

After creating comment we need to replace current form with new form, following view takes care of that.

From the file app/views/comments/create.js.erb delete the line containing following code. Please note that below line needs to be deleted.

$('#comments').append('<%=j render @comment %>');

We need to display the message details and render our component to display comments. Insert following code in app/views/messages/show.html.erb just before <%= render 'comments/comments', message: @message %>

<%= react_component 'CommentList', message: render(partial: 'messages/message.json', locals: {message: @message}) %>

After inserting the code would look like this.

<h1><%= @message.title %></h1>
<p><%= @message.content %></p>
<%= react_component 'CommentList', message: render(partial: 'messages/message.json', locals: {message: @message}) %>
<%= render 'comments/new', message: @message %>

Notice how we are rendering CommentList, based on Message json content from jbuilder view we created.

Step 7 - Setup Subscription to listen to Action Cable from React Component

To listen to new updates to comments, we need to setup subscription from Action Cable.

Add following code to CommentList component.

setupSubscription(){

  App.comments = App.cable.subscriptions.create("CommentsChannel", {
    message_id: this.state.message.id,

    connected: function () {
      setTimeout(() => this.perform('follow',
                                    { message_id: this.message_id}), 1000 );
    },

    received: function (data) {
      this.updateCommentList(data.comment);
    },

    updateCommentList: this.updateCommentList

    });
}

We need to also setup related AC Channel code on Rails end.

Make following code exists in app/channels/comments_channel.rb

class CommentsChannel < ApplicationCable::Channel
  def follow(data)
    stop_all_streams
    stream_from "messages:#{data['message_id'].to_i}:comments"
  end

  def unfollow
    stop_all_streams
  end
end

In our React Component, we use App.cable.subscriptions.create to create a new subscription for updates, and pass the channel we want to listen to. It accepts following methods for callback hooks.

  • connected: Subscription was connected successfully. Here we use perform method to call related action, and pass data to the method. perform('follow', {message_id: this.message_id}), 1000), calls CommentsChannel#follow(data).

  • received: We received new data notification from Rails. Here we take action to update our Component. We have passed updateCommentList: this.updateCommentList, which is a Component method that is called with data received from Rails.

Complete React Component

Here’s how our complete Component looks like.

var CommentList = React.createClass({
  getInitialState(){
    let message = JSON.parse(this.props.message);
    return {message: message};
  },

  render() {
    let comments = this.state.message.comments.map((comment) => {
      return this.renderComment(comment);
    });

    return (
        <div>{comments}</div>
    );
  },

  renderComment(comment) {
    return (
        <article key={comment.id}>
          <h3>Comment by { comment.user.name } </h3>
          <p>{ comment.content }</p>
        </article>
    );
  },

  componentDidMount() {
    this.setupSubscription();
  },

  updateCommentList(comment) {
    let message = JSON.parse(comment);
    this.setState({message: message});
  },

  setupSubscription() {

    App.comments = App.cable.subscriptions.create("CommentsChannel", {
      message_id: this.state.message.id,

      connected: function () {
        // Timeout here is needed to make sure Subscription
        // is setup properly, before we do any actions.
        setTimeout(() => this.perform('follow',
                                      {message_id: this.message_id}),
                                      1000);
      },

      received: function(data) {
        this.updateCommentList(data.comment);
      },

      updateCommentList: this.updateCommentList
    });
  }
});

Step 7 - Broadcast message when a new comment is created.

Our final piece is to broadcast new updates to message to the listeners, that have subscribed to the channel.

Add following code to app/jobs/message_relay_job.rb

class MessageRelayJob < ApplicationJob
  def perform(message)
    comment =  MessagesController.render(partial: 'messages/message',
                                         locals: {message: message})
    ActionCable.server.broadcast "messages:#{message.id}:comments",
                                 comment: comment
  end
end

which is then called from Comment model, like so-

Add this line to Comment model file app/model/comment.rb

after_commit { MessageRelayJob.perform_later(self.message) }

We are using message relay here, and will be getting rid of existing comment relay file - app/jobs/comment_relay_job.rb. We will also remove reference to CommentRelayJob from Comment model, since after_commit it now calls the MessageRelayJob.

Summary

Hopefully we have shown that Action Cable is going to be a good friend of ReactJS in future. Only time will tell.

Complete working example for Action Cable + ReactJS can be found here.

Verifying PubSub Services from Rails using Redis

Let’s say that we have a Service that reads and writes to Redis. We have BaseRedisService for managing connection, RedisWriterService to write to Redis and RedisReaderService to read from Redis.

require 'redis'

# Base class to manage connection
class BaseRedisService
 REDIS_HOST = '127.0.0.1'

 def connection
   if !(defined?(@@connection) && @@connection)
     @@connection =  Redis.new({ host: REDIS_HOST })
   end
   @@connection
 end

end
# Class to write to Redis
class RedisWriterService <  BaseRedisService
 attr_reader :key, :value

 def initialize key, value
   @key, @value = key, value
 end

 def process
   connection.set key, value
 end

end
# Class to read from Redis
class RedisReaderService < BaseRedisService
attr_reader :key

def initialize key
  @key = key
end

def process
  connection.get key
end

end

A test for the above mentioned case might look like this.

require 'test_helper'

class RedisPubSubServiceTest < ActiveSupport::TestCase

def test_writing_and_reading_value_using_redis
  value = 'Vipul A M'

  RedisWriterService.new('name', value).process
  assert_equal value, RedisReaderService.new('name').process
end

end

But now, we need to add PubSub to the service and verify that the service sends proper messages to Redis. For verifying from such a service, the service would need to listen to messages sent to Redis. Problem is that Redis listens in a loop. We would need to explicitly release control from listening and allow our tests to go ahead and verify some scenario.

Lets look at how these services would look.

class RedisPublisherService < BaseRedisService
attr_reader :options, :channel

def initialize channel, options
  @channel     = channel
  @options = options
end

def process
  connection.publish(options, channel)
end

end

and our Subscriber looks like this.

class RedisSubscriberService < BaseRedisService
attr_reader :channel

def initialize channel
  @channel = channel
end

def process
  connection.subscribe(channel) do |on|
    on.message do |channel, message|
      puts message
    end
  end
end

end

Notice that we don’t have control over returning value from the loop easily. Right now we just print on receiving a new message.

Now, lets start persisting our messages to some array in our Service. Also we will start exposing this from a thread variable so that it could be accessed from outside of execution of this listen loop.

class RedisSubscriberService < BaseRedisService
attr_reader :channel, :messages, :messages_count

def initialize channel, messages_count = 5
  @channel        = channel
  @messages       = []
  @messages_count = messages_count
end

def process
  connection.subscribe(channel) do |on|
    on.message do |channel, message|
      messages.unshift message
      Thread.current[:messages] = messages
    end
  end
end

end

We now have a way to access message state from the service to read any messages received by it. Lets say we define a new SubscriberService from a Thread, we could read messages like this.

subscriber = Thread.new { RedisSubscriberService.new('payment_alerts').process }
# Print first message from messages received
puts subscriber[:messages].first

Armed with this, we can now define a set of Rails helpers to use in our Rails tests.

module SubscriberHelpers
THREAD_PROCESS_TIMEOUT = 0.5

def setup_subscriber channel = 'test_channel'
  @subscriber = Thread.new { RedisSubscriberService.new(channel).process }
end

def teardown_subscriber
  @subscriber.kill
end

def with_subscriber
  yield
  @subscriber.join THREAD_PROCESS_TIMEOUT
end

def message_from_subscription
  @subscriber[:messages].first
end
end

Notice the with_subscriber method. It executes some code passed to it, then passes method execution to the subscriber process to read any messages sent and store onto messages store.

The count of the variable THREAD_PROCESS_TIMEOUT, can be experimented to set to a value that suites the system that’s being verified.

In our tests, we can now verify PubSub as-

require 'test_helper'

class RedisPubSubServiceTest < ActiveSupport::TestCase
include SubscriberHelpers

def setup
  setup_subscriber
end

def teardown
  teardown_subscriber
end

def test_writing_and_reading_back_values_from_pub_sub
  value = 'Vipul A M'

  with_subscriber do
    RedisPublisherService.new('test_channel', value).process
  end

  assert_equal value, message_from_subscription
end
end

Summary

We took a look at how PubSub based services can be verified by using threads and exposing messages from them, for verification. These can be tailored to support any similar PubSub service like Redis, and can be used to easily verify values being published from our services from Rails tests.