Blog

Testing Rails Applications on Real Mobile Devices (both design and features such as camera access).

Glen Crawford
December 18, 2020

As more and more people start using their mobiles as their primary devices, both for personal and work purposes, we have gotten an increasing number of clients requesting features that make use of the capabilities that their mobile devices offer over regular computers. While these are certainly more fun to develop than a (let’s be honest) vanilla Rails app, they can offer challenges, such as how to test them effectively.

There are plenty of ways to do so; many browsers nowadays offer a way to simulate different screen sizes, device orientations, and pixel ratios, such as Responsive Design Mode in Firefox. You can also use emulators, VMs, and services like BrowserStack. You have lots of options to simulate, but I want to briefly outline how to use real devices to test your apps running on your local Rails server. The benefits of this approach are:

  • You can test on real, physical devices (if you have them), meaning that you don’t have to trust the accuracy of emulators.
  • You’ll be running against your local development environment, meaning that you can use your standard development tools and workflow (e.g. debuggers) and you don’t need to package and deploy the app anywhere first.

The Easy Way (99% of cases)

If your app is quite basic and you just want to test that your responsive UI design works, then you hardly have to do anything. You can expose your Rails server to serve over your home or office network, and connect to it by simply browsing to your computer’s network IP address in the browser on your mobile device. Simply start the Rails server like so:

bash rails server -b 0.0.0.0

Then run the following in your terminal to find your computer’s IP address on your local network (it will likely look something like 192.168.x.x):

bash ifconfig | grep inet

(On Windows use ipconfig instead). Then grab your phone (also connected to the same network), open the browser, and navigate to http://192.168.x.x:3000. And that’s it! You will now be browsing your Rails application served by your computer’s development environment to your phone over your network.

The Hard Way (for the other 1% of cases)

There is a key problem with the first approach, and that is that the connection will be over HTTP. Unless you want to go down the path of editing your /etc/hosts file to resolve a domain to localhost, creating a self-signed SSL certificate, and configuring your browser and server to use the certificate, you won’t be able to run your Rails application locally via SSL (HTTPS).

The thing is, in some cases you are going to need to test your app via HTTPS. This is because modern browsers restrict access to device resources such as the camera and microphone so that they only run in a secure context. As explained by the following excerpt from Mozilla’s documentation for MediaDevices.getUserMedia(), which controls access to device resources such as the camera and microphone: > getUserMedia() is a powerful feature which can only be used in secure contexts. In insecure contexts, navigator.mediaDevices is undefined, preventing access to getUserMedia(). A secure context is, in short, a page loaded using HTTPS or the file:/// URL scheme, or a page loaded from localhost.

As you can see, you must be in a secure context (a big part of which is HTTPS) in order to access this API. An exception to this is localhost, so you can test things locally. But we need to connect from a separate mobile device.

You can see this in action by testing the value of the JavaScript expression window.isSecureContext, which according to the documentation “indicates whether a context is capable of using features that require secure contexts”. On http://localhost:3000 from your computer, this value will be true, and on http://192.168.x.x:3000 from your mobile device this value will be false.

So, how can we easily connect to our development environments on our mobile devices via HTTPS? Enter ngrok, a service that creates a public and temporary HTTPS URL that tunnels to your locally-running development server, exposing it to the internet, which you can then open up on your mobile device. Exposing your development environment to the world might make you a little (justifiably) uncomfortable, however the tunnels are time-limited, you can sever the connection when you’re done with it, and the domain is a long random string that no one is going to be able to guess. Let’s set it up the easy way, via Homebrew:

bash brew cask install ngrok ngrok http 3000

At this point, if you are running a modern version of macOS, it may prevent the app from running since it is an untrusted third-party application. You may have to add an exception via System Preferences > Security & Privacy > General.

When you run ngrok, the tunnel will be established, a domain will be assigned, and you will see the following output, showing you that your ngrok domain is now ready to forward to your local development environment via both HTTP and HTTPS:

bash Session Status online Session Expires 7 hours, 59 minutes Version 2.3.35 Region United States (us) Web Interface http://127.0.0.1:Matenia RossidesMatenia Rossides Forwarding http://REDACTED.ngrok.io -> http://localhost:3000 Forwarding https://REDACTED.ngrok.io -> http://localhost:3000

The last thing you have to do is open config/environments/development.rb, add the following line and restart the server to allow serving requests to the ngrok domain:

ruby config.hosts << 'insert_ngrok_domain_here.ngrok.io'

If you wanted to be really fancy, you could use a regular expression, as you will get a new domain from ngrok each time:

ruby config.hosts << /[a-z0-9]+\.ngrok\.io/

And that’s it! Grab your mobile device, navigate to the ngrok domain, and your app will load via HTTPS. Since you are now in a secure context you will now be able to test your app’s features that rely on being in one, such as those that need access to the camera.