Android: How to test Local Web Apps on an Emulated Device (AVD)

Android AVD running local Web App

Editing your /etc/hosts file is great for running and testing web apps as they are under development. For a project I’m working on, I needed to be able to access one of my local Rails apps through an Android device, which meant editing the device’s /etc/hosts file. As I haven’t rooted my Nexus-S, so opted to use an emulated Android Virtual Device (AVD), as they are configured by default to allow root access.

I started by creating a simple hosts file on my desktop. It’s this file that I would push to the AVD

cd Desktop
vim hosts # or your favourite text editor....

Use your text editor to create a simple hosts file pointing to your local web app. Remember to also include a localhost entry:

  # hosts
  127.0.0.1       localhost 
  192.168.1.10    rails-app

Next, copy your new hosts file to the AVD:

adb push hosts /etc/hosts

Access Denied

Despite having root access, though, adb wouldn’t let me push the new hosts file because the system partition is mounted as read-only. You can remount the system partition in read-write mode using adb remount, and then try pushing the hosts file up to the device:

adb remount
abd push hosts /etc/hosts

I kept getting an Out of Memory error, which seems to be a common problem. The solution (gleaned from scattered forum posts) is to use the emulator’s -partition-size option.

Using this option means you won’t be able to launch the AVD directly from Eclipse, but instead need to use the command line. Close down any running AVDs, and then run, and then re-launch the AVD passing in the -partition-size option with a reasonable value:

emulator -avd Samsung_Galaxy-Tab -partition-size 128
 
# ...wait the avd to boot up...
 
adb remount
abd push hosts /etc/hosts

The hosts file should now successfully be copied to your AVD. If you launch the AVD’s browser and enter the local URL from your hosts file (e.g. http://rails-app:3000/), the AVD will connect to the local IP address you specified.

Note: You’ll need to keep hold of your hosts file as your settings will be wiped when you shut down the AVD. You can reinstall the file next time by performing the adb remount; adb push hosts /etc/hosts script each time you boot the AVD.

References

  1. Google Groups Thread
  2. Cute Android Tips: Failed to Copy File to System

Rails 3: How to Autoload and Autorequire your Custom Library Code

Every time I start a new Rails 3 project, I’m always caught out by its autoloading behaviour. Rails 3 will only require (and so autoload) a module when it is first encountered within the application code, for example by a call to include or require.

Whilst the reasoning behind this decision is sound, I usually just want to load some common functionality into, for example ActiveRecord, and have it available to all of my models.

So, as a reminder to myself and to help anyone else caught out by this, here is how to autoload (and autorequire) your own library code in Rails 3:

Ensure that your library code’s path is set in config/application.rb. By default, Rails 3 autoloads from a /extras folder, but I conventionally keep custom library code in a /lib folder:

# config/application.rb
config.autoload_paths += %W(#{config.root}/extras #{config.root}/lib)

Next, we need to tell Rails to require our library code (so it is available to the application). Create a new initializer called application.rb in config/initializers and require your library modules:

# config/initializers/application.rb
require 'my_modules'
require 'my_modules/active_record/active_record_extensions'
# ... require any other custom modules your application uses

All that’s left to do is restart your Rails server to load your custom modules into the application. Remember that if you change your custom code, you’ll need to restart the server again to reload the changes.

Android: Spinner-Like UI for Selecting Multiple Options

Download the source code files AndroidMultipleChoice.tar.gz (tar.gz, eclipse project)

Android includes a Spinner control that works very much like a desktop drop-down (or combo-box) control. Tapping a Spinner presents a list of options, and allows the user to select one from the list.

However, in building a small research app, I needed to allow users to select multiple items from the Spinner’s list. From what I could see, though, the Spinner class is not capable of doing this, so I built a small throwaway app that implements this oft-requested functionality.

Getting Started

Spin up a new Android application in Eclipse, creating an activity named MultipleChoiceActivity. For reference, I’m targeting the Google Android 2.1 APIs (Level 7).

Once the project is created, open up and edit the main.xml file to display a simple label and button. I’ve used a Button instead of a Spinner as we can change the button’s label to indicate which options have been selected:

<!-- res/main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  android:padding="5dip">
 
  <TextView 
    android:text="Select Colours"
    android:id="@+id/textView1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="5dip" />
 
  <Button 
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:text="- None Selected -"
    android:id="@+id/select_colours"
    android:padding="5dip" />
</LinearLayout>

Building the Activity

For this example, I’m using a hard-coded list of colours here in this example (rather than, for example, hooking up to a database). Start by hooking up the interface to properties in MultipleChoiceActivity.java:

// src/com/example/multiple_choice/MultipleChoiceActivity.java
 
// ... package, imports ...
 
public class MultipleChoiceActivity extends Activity implements OnClickListener {
  protected Button selectColoursButton;
 
  protected CharSequence[] colours = { "Red", "Green", "Blue", "Yellow", "Orange", "Purple" };
  protected ArrayList<CharSequence> selectedColours = new ArrayList<CharSequence>();
 
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
 
    selectColoursButton = (Button) findViewById(R.id.select_colours);
    selectColoursButton.setOnClickListener(this);
  }
 
  @Override
  public void onClick(View view) {
    switch(view.getId()) {
      case R.id.select_colours:
        // TODO: Show the colours dialog
        break;
 
      default:
        break;
    }
  }
}

With that code, your button is now hooked up to listen for clicks. The colours array is a simple list of colours that will be displayed when we click the button. The selectedColours ArrayList is a dynamic array of the colours that have been selected. Using ArrayList lets us easily add and remove colours when the user changes the selection.

Try running the app in the Android emulator (or on a device) to check that everything works so far.

Displaying the Options

Next, we’ll use Android’s AlertDialog to let us display the list of colours, and allow the user to make selections. AlertDialog comes with built-in functionality to allow multiple selections, and automatically adds checkboxes to our list interface.

Add the following method to MultipleChoiceActivity.java:

// src/com/example/multiple_choice/MultipleChoiceActivity.java
protected void showSelectColoursDialog() {
  boolean[] checkedColours = new boolean[colours.length];
  int count = colours.length;
 
  for(int i = 0; i < count; i++)
    checkedColours[i] = selectedColours.contains(colours[i]);
 
  DialogInterface.OnMultiChoiceClickListener coloursDialogListener = new DialogInterface.OnMultiChoiceClickListener() {
   @Override
    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
      if(isChecked)
        selectedColours.add(colours[which]);
      else
        selectedColours.remove(colours[which]);
 
      onChangeSelectedColours();
    }
   };
 
  AlertDialog.Builder builder = new AlertDialog.Builder(this);
  builder.setTitle("Select Colours");
  builder.setMultiChoiceItems(colours, checkedColours, coloursDialogListener);
 
  AlertDialog dialog = builder.create();
  dialog.show();
}

showSelectColoursDialog is the method that will be called when tapping the button. It starts by walking through the colours array and checking which colours are already in the selectedColours ArrayList. The results get stored in an array of booleans (checkedColours) that will be used by the AlertDialog to determine which items in the list are to be checked.

Next, we build a DialogInterface.OnMultiChoiceClickListener that will be invoked when the user checks or unchecks a colour in the list. Depending on the state of the check box (supplied via the isChecked parameter), we add or remove the colour from the selectedColours ArrayList.

Notice that when the listener is finished, we call an as-yet undefined method, onChangeSelectedColours. This will be a callback method that we’ll use to update the button’s label:

// src/com/example/multiple_choice/MultipleChoiceActivity.java
protected void onChangeSelectedColours() {
  StringBuilder stringBuilder = new StringBuilder();
 
  for(CharSequence colour : selectedColours)
    stringBuilder.append(colour + ",");
 
  selectColoursButton.setText(stringBuilder.toString());
}

This simple callback method just walks through the ArrayList of selected colours, and builds a string containing the name of each colour.

Finally, all that’s left to do is hook up our button to call showSelectColoursDialog in the onClick method we overrode earlier:

// src/com/example/multiple_choice/MultipleChoiceActivity.java
@Override
public void onClick(View view) {
  switch(view.getId()) {
    case R.id.select_colours:
      showSelectColoursDialog();
      break;
 
    default:
      break;
  }
}

With everything hooked up, it’s time to test out the app. Run the emulator (or install to a device), tap the button and you’ll be able to select multiple colours from the list. If you tap the back button, the list will close, and your button’s label will have updated to show the colours you tapped. Try tapping the button again, and your previously selected colours will still be checked.

Summary

Hopefully this simple example will be useful to anyone looking to implement multiple-choice options. It would be nice to use the Spinner gadget rather than a Button, perhaps by subclassing Spinner and overriding it’s click handler and label drawing methods. I haven’t tried this – let me know in the comments if you decide to give it a go.

Rails 3: How to Simulate Paperclip Attachments With FactoryGirl

In developing the next phase of markstocks.com, I needed to simulate a file upload attribute in my FactoryGirl factories. A quick Google revealed some promising code, but everything out there was based on Rails 2.

There’s been a lot of changes in Rails 3, so using what I found, I tweaked the code to work in my Rails 3 factories. I’ve also posted this code as a gist forked from the original Rails 2 version on Github.

# spec/spec_helper.rb
...
# Support for Paperclip factories (add this before you load your factory definitions)
include ActionDispatch::TestProcess
...
# spec/support/factory_attachment.rb
Factory.class_eval do
  def attachment(name, path, content_type = "image/jpg")
    path_with_rails_root = "#{Rails.root}/#{path}"
    uploaded_file = fixture_file_upload(path_with_rails_root, content_type)
 
    add_attribute name, uploaded_file
  end
end
# spec/factories/photos.rb
Factory.define :photo do |p|
  # Given a Photo model with has_attached_file :image
  p.attachment :image, "spec/support/sample_photo.jpg"
end

References

  1. Original Gist
  2. APIDock.com

Lightweight Web Apps: Getting Started With Sinatra

For many reasons, I’m a huge fan of Rails for building web software, and by implication, coding in Ruby. When you’ve spent a little time working with Ruby, it’s difficult to go back to more traditional languages such as PHP.

For less intense website or small applications, though, Rails can feel a bit heavy-handed. Whilst Rails 3 goes a long way to improving this, I’ve recently been trying out the lightweight ruby framework, Sinatra.

Sinatra is a barebones framework for getting web applications up and running quickly. The idea is that Sinatra gives you a base into which you pull together the things you need, effectively building your own mini-framework. The process is enhanced by the vast array of Ruby Gems that are available.

In this post, I’ll show how to build a simple Sinatra application configured with Bundler and running on Rack that lets you quickly start building lightweight web applications.

Creating Your Sinatra Project

Unlike Rails, Sinatra doesn’t come with generators, so you’ll need to create the project layout yourself. Whilst you can use your own folder layout, there are a few conventions for which Sinatra is configured. Something like this should be good to get started:

mkdir -p myproject myproject/views myproject/public myproject/public/javascript myproject/public/css myproject/public/images
touch myproject/app.rb myproject/config.ru myproject/Gemfile

Running these commands generates the following folder structure:

myproject/
  public/
    public/css
    public/images
    public/javascript
  views/
  tmp/
  app.rb
  Gemfile
  config.ru

If you’ve used Rails 3, or worked with the Bundler gem and Rack, most of this should look familar: Gemfile is used by Bundler to declare rubygems the project relies on, whilst config.ru is used by Rack to configure and run the application.

Bundling Gems

Next, edit the Gemfile to load Sinatra and any dependencies. My markup of choice for HAML for layout (HTML) and SASS for CSS stylesheets. Sinatra makes using HAML (or any other renderer, such as ERB) very simple:

# Gemfile
source :rubygems
 
gem "sinatra"
gem "haml"

To install the bundle, just run bundle install from within your project folder:

cd myproject
bundle install

Configure Sinatra to run on Rack

My development environment is setup to run Ruby projects on Rack using the Passenger gem. To configure Sinatra to run on Rack, our project just needs a config.ru file. This file tells Rack to load the any required gems and star your Sinatra application:

# Gemfile
require "rubygems"
require "bundler/setup"
require "sinatra"
require "haml"
require "app"
 
set :run, false
set :raise_errors, true
 
run Sinatra::Application

Build Your App

With the environment configured, it’s time to build a small app to test everything. Start by adding a root path to app.rb and a corresponding index.haml file under views/:

# app.rb
set :haml, :format =&gt; :html5
 
get "/" do
  haml :index
end
# views/index.haml
%html
  %head
    %title My Sinatra App
 
  %body
    %h1 Hello World
    %p Your app is up and running!

The get block routes any HTTP GET requests for the site’s root path (example.com/) and renders views/index.haml using the HAML parser.

Running Your Application

To see your application running, start Rack by calling rackup from your project directory.

cd myproject
rackup

Now navigate to localhost:9292 to see your Sinatra app working! All being well, you should be greeted with the following:

Summary

Initially I had trouble seeing how Sinatra would be useful given the existence of full-stack frameworks like Rails. However, as I’ve taken the time to learn Sinatra, I can see the benefits of such a lightweight framework when used for certain tasks.

Whilst it shouldn’t be thought of as a replacement for frameworks like Rails, Sinatra is another tool available to Ruby developers looking to quickly build and deploy small websites and applications.

When Should You Use Sinatra?

When you should use Sinatra over a larger framework like Rails is entirely dependent on the requirements of your site. Sinatra is capable of connecting with databases using gems like ActiveRecord or DataMapper in the same way Rails is. It’s feasible, then, to build large-scale web applications with Sinatra – but my personal preference would be to stick with Rails.

The rule of thumb I’m using at the moment is that if my app requires a database, I’ll build it in Rails, otherwise I’ll try Sinatra.

With that in mind, I’m now using Sinatra to build and run lightweight websites such as the recently launched portfolio of Mark Stocks. Mark’s site only requires simple server-side processing for handling contact forms – a full-blown Rails build seemed a be too much! Sinatra provided just the right base on which to build Mark’s site, whilst retaining the flexibility that comes with the Ruby ecosystem.

Next Steps

In the next tutorial, I’ll extend the basic framework we’ve started here to include of a number of useful Ruby gems built for Sinatra, and show how to use your own custom helper code. When it’s a little more polished, I’ll also publish my working Sinatra base application on github.

References

  1. The Sinatra Website
  2. The Official Sinatra Book
  3. Bare Sinatra App For Deploying To Passenger