Learn to program for fun

I’ve had a couple of people ask me how they can learn to program, so I wanted to write something up about how I would go about it, if I were starting today. Caveat: I’m only referring to web programming (web sites), not programming for other platforms such as mobile (iOS or Android), Raspberry Pi, etc…  However I would think that the steps are similar.

  1. Buy your domain: This is your http://www.mydomain.com web address. The reason I mention buying your domain first is that you don’t want yours to get taken. Domains are disappearing every day ( Mine is http://www.hoitomt.com. The domain will cost you less that $15/year and you can just sit on it until you intend to do something about it. I own all of my domains through GoDaddy.com but you can buy them through any Registrar, it makes no difference. See number 4.
  2. Learn HTML and CSS: take CodeAcademy classes: Start with Web Fundamentals.  This will give you the basics of HTML and CSS. Do not use an IDE like Eclipse, NetBeans, or anything else like that. Only use a text editor for your websites for now. I recommend SublimeText, but you can use Notepad, among other options as well.
  3. Find an desire: This is idea for a website/project that you want to work on. This can be a website for a friend, for yourself, for your cousin’s business, anything really. This should really happen as your second step but going through the class work will help you better frame your idea.
  4. Learn to deploy: Pick a web host – if you are using only HTML and CSS there are a lot of good options out there (GoDaddy.com and Bluehost.com are two hosts that I’ve used). To keep things easy, buy your domain from the same place as you host your site. Once you get your idea started, push it out to your domain. This is a very gratifying experience. It’s awesome to see your hard work on display on the actual internet.
  5. Write Code: lots and lots of code.  I had a professor that said “You don’t learn to drive a car by reading a book – programming is the same way”.  You have to write code to get better at programming. If you have a strong enough desire to see your idea (number 3) come to fruition, this part is easy.  You will want to write the code.
  6. Learn a server side language and framework: My recommendation is Ruby on Rails.  Ruby is the programming language, Rails is the framework. Not only is ROR very easy to use but if you get good enough at it, you can get a pretty good job as an ROR programmer.  Start with the Ruby course from CodeAcademy
  7. Learn about databases (only a little): This is really 7a, the language/framework step will cover some database stuff. Once you get to this point, you’re going to have run into a situation where you wish you had a database.  Everything online (user information, pictures, products, etc…) is stored in a database.

Notes about learning

Programming is a tool, you use it to make things. You wouldn’t buy a hammer unless you had some nails that needed to be driven, you wouldn’t buy a spatula unless you has some eggs that needed flipping, and, likewise, there isn’t a need to program unless you have something that you want to make. So my first piece of advice is to answer the question: What do you want to make?

When we are young we learn because we are told to learn.  To get by in the world do we need to know Algebra?  State Capitals? History of the American Revolution?  No, no and no, but they told us to learn it, so we did. However, starting in college you start to say to yourself “Why the hell am I learning this?  I’m never going to use it and I don’t give a damn about it”.  Learning takes time, and sometimes money, both of which are scarce resources. So, as an adult, we tend to learn only those things that help us to satisfy a desire or need.

This is a pretty good start, if you make it to the last step you will probably know what you want to do next.  Please contact me via the comments or by email if you want any more information.  Good Luck!

Inline validation with Ruby on Rails 3.1 and jQuery

Hi,

I’m going to go over inline form validation (with helpers) similar to how MailChimp does it on their sign up page at: https://mailchimp.com/signup/.  When you click on the form text box a helper slides out from the bottom of the input box. Then after you exit the text box it validates the data that you just put into the field.  It is a super nice way to do helpers on your input forms and validation for your forms.  Our goal is to avoid the standard big red Ruby on Rails error that we’ve come to know and love.

Note that some of the formatting in this blog post was removed.  I think everything is still readable but if not check out the source code. You can get the source code of this tutorial from my GitHub repository: https://github.com/hoitomt/tut_inline_validation

Create the Project

I’m going to start out with a simple rails project and use scaffolding to create a simple form. We will be modifying the html and css so that our validation works the way we want it to.


$ rails new tut_inline_validation

$ rails g scaffold person first_name:string last_name:string

$ rake db:migrate

Next update your Gemfile to include the client_side_validations gem


source 'http://rubygems.org'

gem 'rails', '3.1.3'

gem 'sqlite3'

gem 'client_side_validations'

# Gems used only for assets and not required

# in production environments by default.

group :assets do

  gem 'sass-rails',   '~> 3.1.5'

  gem 'coffee-rails', '~> 3.1.1'

  gem 'uglifier', '>= 1.0.3'

end

gem 'jquery-rails'

group :test do

  # Pretty printed test output

  gem 'turn', '0.8.2', :require => false

end

Then install your bundle


$ bundle install

Configure client_side_validations

The client_side_validations gem requires a bit of setup. The instructions are listed on the GitHub site for the gem and are as follows:

  1. Run the generator for client_side_validations. NOTE: on the github page for client_side_validations it states that an additional generator needs to be run for Rails 3.1+. I did not need that generator (copy_assets) so it isn’t listed.
  2. Update application.js to include the rails.validations path
  3. Update the generated initializer (config/initializers/client_side_validations.rb)
  4. Update your form to use validation

Number 1: Run the generator

$ rails g client_side_validations:install

      create  config/initializers/client_side_validations.rb

*********************

ClientSideValidations

*********************

In your app/assets/javascripts/application.js file add the following:

//= require rails.validations

$

Number 2: Update application.js

After you run the generator there is an instruction at the bottom of the file. We need to update application.js so that it includes the validation code


// This is a manifest file that'll be compiled into including all the files listed below.

// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically

// be included in the compiled file accessible from http://example.com/assets/application.js

// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the

// the compiled file.

//

//= require jquery

//= require jquery_ujs

//= require_tree .

//= require rails.validations

Number 3: Update the initializer


# ClientSideValidations Initializer

require 'client_side_validations/simple_form' if defined?(::SimpleForm)
require 'client_side_validations/formtastic'  if defined?(::Formtastic)
# Uncomment the following block if you want each input field to have the
# validation messages attached.
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  unless html_tag =~ /^<label/
    %{</pre>
<div class="field_with_errors">#{html_tag}<label class="message" for="#{instance.send(:tag_id)}">#{instance.error_message.first}</label></div>
<pre>}.html_safe
  else
    %{</pre>
<div class="field_with_errors">#{html_tag}</div>
<pre>}.html_safe
  end
end

Number 4 Update the form to use validation.

Open app/views/people/_form.html.erb and update your form_for to add validate => true. I also added an ID to make it easier for jQuery to find the form

</pre>
<%= form_for(@person, :validate => true, :html => {:id => 'awesome-form'}) do |f| %>
<pre>

Now let’s start up the server


$ rails s

If you navigate to http://localhost:3000/people you should see your person/index.html.erb file. So Far so good.

Add Model Validation

Go to person.rb (app/model/person.rb) and add the following validations. Both the first and last name are required. The length of the first name must be between 3 and 30 characters and the last name must be unique.


class Person < ActiveRecord::Base
  validates :first_name, :presence => true,
                         :length => { :within => 3..30 }

  validates :last_name, :presence => true,
                        :uniqueness => { :case_sensitive => false }

end

Let’s make sure they work. From http://localhost:3000/people click on the ‘New Person’ link. Don’t enter anything in the fields and click on “Create Person”.  You should see the following:

Now we know that validations are working. You can see the client_side_validations is doing some nice work already.  It added in the inline validations to the right of the fields and didn’t display the big red box at the top of the form.

jQuery Goodness

Let’s improve the look a bit. Open up app/views/people/_form.html.erb file. Remove the error display and update the html as follows:

 true, :html => {:id => 'awesome-form'}) do |f| %></pre>
<div id="data-entry" class="clearfix">
<div id="label"></div>
<div id="field">
<div id="person_first_name_helper" class="helper">e.g. Barack</div>
<div id="person_first_name_error"></div>
</div>
</div>
<div id="data-entry" class="clearfix">
<div id="label"></div>
<div id="field">
<div id="person_last_name_helper" class="helper">e.g. Obama</div>
<div id="person_last_name_error"></div>
</div>
</div>
<div class="actions"></div>
<pre>

The code above adds containers for the helpers and the error messages so that jQuery has somewhere to put our errors. Now that we have the form html done, let’s add the jQuery. We’ll use Unobtrusive javascript so create a file called sign_up_form.js and put it into app/assets/javascripts

$(function() {
	hideAllHelpers();

	$('#person_first_name').focus(function() {
		$('#person_first_name_helper').show(200);
	});
	$('#person_first_name').blur(function() {
		$('#person_first_name_helper').hide(200);
	});

	$('#person_last_name').focus(function() {
		$('#person_last_name_helper').show(200);
	});
	$('#person_last_name').blur(function() {
		$('#person_last_name_helper').hide(200);
	});

	clientSideValidations.callbacks.element.after = function(element, eventData) {
		// element is the input element (text field). The text field is wrapped by
		// the error so the parent is the error_wrapper. The label is a child of
		// the wrapper and the html of the label is the actual error message
		var elementContainer = element.parents('#field');
		var errorLabel = element.parent().find('label');
		var errorMsg = errorLabel.html();
		errorLabel.hide();
		var existingError = elementContainer.find('#validation-error');
		console.log("Error Msg: " + errorMsg);
		if(!errorMsg || errorMsg == null) {
			existingError.remove();
		} else if(existingError && existingError.length > 0) {
			existingError.html(errorMsg);
		} else {
			elementContainer.append('</pre>
<div id="validation-error">' + errorMsg + '</div>
<pre>
');
		}
	}

});

function hideAllHelpers() {
	$('#person_first_name_helper').hide();
	$('#person_last_name_helper').hide();
}

Here is what the code above is doing:

  • The hideAllHelpers() function is defined at the end of the script.  This hides the helpers upon load
  • The next 8 lines of code show and hide the helpers depending on which text box you are in
  • The clientSideValidation callback is provided by the client_side_validations gem. When Rails validates your field it wraps each text box/label combo in a div. The client_side_validations callback is doing the heavy lifting by making the validation error available to us in javascript.  We work through the DOM to put the error in the correct place.  In the case of this exercise we want the error to end up under the text box.

If you go to http://localhost:3000/person/new you should now see that when you click into a box a helper slides out from underneath.  When you leave the text box it will show a validation error if the text is invalid.

All of the code is on GitHub under https://github.com/hoitomt/tut_inline_validation.  I’ve included a stylesheet out there to help make your form/helpers/validations look awesome.

Thanks for Reading!

References
http://railscasts.com/episodes/263-client-side-validations – It almost goes without saying that one of Ryan Bate’s screen casts would be a reference for a Rails tutorial. He is the king of Rails teaching. Specifically episode 263 is important because it covers the client_side_validations gem

Use Custom Fonts in Ruby on Rails 3.1 with the asset pipeline

Just a quick post on something I just learned.  If you want to use a custom font in a ROR 3.1 project start with this post: http://spin.atomicobject.com/2011/09/26/serving-fonts-in-rails-3-1/

Sidebar: FontSquirrel is awesome, the kit is really helpful. It’s another one of those really fantastic web projects that somebody put out there for free.

Anyway, after you get the font kit downloaded and have it unzipped into app/assets/fonts look in the stylesheet.css file in the kit.  There is some CSS that you can use to get started. Update the css to support the asset pipeline. You have to structure your URLs as follows:

@font-face {

font-family: ‘DroidSerifRegular’;
src: url(/assets/DroidSerif-Regular-webfont.eot);
src: url(/assets/DroidSerif-Regular-webfont.eot?#iefix) format(’embedded-opentype’),
url(/assets/DroidSerif-Regular-webfont.woff) format(‘woff’),
url(/assets/DroidSerif-Regular-webfont.ttf) format(‘truetype’),
url(/assets/DroidSerif-Regular-webfont.svg#DroidSerifRegular) format(‘svg’);
font-weight: normal;
font-style: normal;

}

Finally, if you are using Chrome for development it will throw an error like “Resource interpreted as Font but transferred with MIME type application/octet-stream”.  To fix this update config/initializers/mime_types with this line:

Mime::Type.register “font/opentype”, :font

That will fix the Chrome error.  Cheers and thanks to the Intertubes for the help:

http://spin.atomicobject.com/

http://www.fontsquirrel.com/

http://stackoverflow.com/questions/2871655/proper-mime-type-for-fonts

Java and Ruby, Rails and Spring

I’m in the middle of studying for the Core Spring Essentials Certification exam and wanted to put a couple of thoughts out there with regards to Spring and Java for the Web. Spring has a nice web framework know as Spring MVC. It doesn’t need a JEE container to run so it runs on Tomcat and other non-enterprise servers. I think a person could get it set up on a PAAS like Heroku, now that they have Java support.  So it makes a very viable option for developing web applications for personal and freelance projects.

However I don’t know why anybody would use it for that.  If you are a Java developer and don’t know Ruby on Rails, or one of the other newer web language/framework combos, I suppose Spring MVC would be a good option.  But compared to ROR, Spring MVC seems like a much more complex way to solve the exact same problem: serve dynamic web pages with data pulled from a database mixed with static content.

I know that Spring will integrate into a Java environment that supports messaging, transactions, and any other enterprise bits that you need. But ROR can do some of those things as well and, really, how many sites really need a full enterprise backend? I’m a J2EE dev in my day job so I’m tempted to use a Java framework for my side projects as well, as a way of improving my skills. But using Spring MVC seems like overkill.

I really don’t mean to bash Spring or to criticize Spring MVC. Spring is a great framework and it makes Java Enterprise Programming much easier. I understand that if you are a Java programmer and want to start web programming on the side, then Spring MVC (and probably Spring ROO) are a perfect starting point for you. But my advice would be to learn one of the new “scripting” languages (ROR) or Javascript/Node.js/Backbone.js.

Build-a-server

Whether you are interested in Node.js or not there is a really excellent beginner “book” here.  What makes the tutorial/book so interesting, and valuable, is that you end up building a web server.  Granted, Node.js is doing all of the serving of the pages but the tutorial walks you through the request/response lifecycle. It feels like you are coding “close to the metal” of the server machine, and it’s all done using familiar javascript.

You get started with the ubiquitous Hello World example and work your way up to a router, request handlers, and everything else that goes into a website.  The steps are small and each one is explained quite well.  You don’t need to know javascript to do the tutorial, but it helps if you have used it a bit.

I haven’t done much coding with PHP so if you come from a PHP background, the tutorial may be old news.  However If you come from a Ruby on Rails background the tutorial really helps to tie together a lot of what we are doing in the config/routes file and how the MVC pattern works. At the very least, regardless of your background, it’s a great introduction to Node.js.

It’s like a lot of things: You don’t need to understand how it works in order to get by.  But if you understand how it works, you can use it better.  This tutorial does an excellent job showing you how a web server works.  And you get to learn Node.js in the process, what could be better!

Here is the link to the book again: http://nodebeginner.org/

Sencha Touch application with Ruby on Rails – Part 2

The source code for this application is posted on GitHub at https://github.com/hoitomt/Sencha-Tutorial

Sencha has formalized the MVC pattern recently as part of the ExtJS 4 release.  Check out this link for more information.

Create the Sencha Application

I’m back with the Sencha portion of the application.  We are going to create the application using the MVC (Model View Controller) pattern

Update your Rails App

In your rails public/javascripts directory create the following folders.

app

app/controllers

app/models

app/views

Add the sencha touch folder to the public/javascripts folder.  Take a look at the Hello World application from Sencha for some assistance on downloading the zip file containing all of the applicable files.  I downloaded it and extracted the entire package into public/javascripts/.  Then I renamed the folder touch_1_0_1.  So public/javascripts/touch_1_0_1 has the following directories: docs, examples, jsbuilder, pkgs, resources, src, and test.  It also contains some of the other files that come with the Sencha touch download.

Now copy the stylesheet over to a directory that Rails likes.  From public/javascripts/touch_1_0_1/resources/css copy “sencha-touch–debug.css” over to public/stylesheets/.  If you did the first part of this tutorial, then you will now have scaffold.css and sencha-touch-debug-css in the public/stylesheets directory.

Update your index file with the references to the Sencha Touch file and stylesheet.  Here is my index file.


<% if(mobile_device?) %>

 <!-- Code Viewable to mobile devices -->
 <%= content_for :head do %>
 <%= stylesheet_link_tag 'sencha-touch-debug' %>
 <%= javascript_include_tag 'touch_1_0_1/sencha-touch-debug' %>

 <style>
 .synced {
 background-color: #EDE613;
 }
 </style>

 <% end %>

<% else %>
 <%= content_for :head do %>
 <%= stylesheet_link_tag 'scaffold' %>
 <%= javascript_include_tag :defaults %>
 <% end %>
 <h1>Listing contacts</h1>

 <table>
 <tr>
 <th>First Name</th>
 <th>Last Name</th>
 <th>Email</th>
 <th>Phone</th>
 <th></th>
 <th></th>
 <th></th>
 </tr>

 <% @contacts.each do |contact| %>
 <tr>
 <td><%= contact.first_name %></td>
 <td><%= contact.last_name %></td>
 <td><%= contact.email %></td>
 <td><%= contact.phone %></td>
 <td><%= link_to 'Show', contact %></td>
 <td><%= link_to 'Edit', edit_contact_path(contact) %></td>
 <td><%= link_to 'Destroy', contact, :confirm => 'Are you sure?', :method => :delete %></td>
 </tr>
 <% end %>
 </table>

 <br />

 <%= link_to 'New Contact', new_contact_path %>

<% end %>

Create the Sencha App

Starting point: app.js

Now you should be ready to start building the application. Let’s start with the entry point into the application, the app.js file.  Put the app.js file into public/javascripts/app. The code below creates an instance of the viewport that will be used to display our panels. The Sencha API it give some helpful information about Ext.regApplication. The Sencha API will be your BFF as you build more applications. Creating your application with the regApplication function automatically creates your app.views, app.models, app.stores, and app.controllers namespaces which makes it easy to navigate through your application

Ext.regApplication(
  {
    name: 'app',
    launch: function() {
    this.views.viewport = new this.views.Viewport();
  }
});

Views: Viewport.js

Now let’s create the Viewport.js file.  Put the Viewport.js file in public/javascripts/app/views.  The code below sets up the main panel that will provide the navigation for all of your sub-panels.  When navigating between slides the code will actually be switching the active panel in the viewport.  The viewport below shows all of the panels in the application.  We haven’t created these yet so your application will crash if you try to run it right now.  You can go ahead and create empty files for the 5 files below (ContactsList, ContactShow, ContactEdit, ContactNew, and ContactCatalog).  Put them all into public/javascripts/app/views.

//app.views.Viewport
app.views.Viewport = Ext.extend(Ext.Panel, {
  fullscreen: true,
  layout: 'card',
  cardSwitchAnimation: 'slide',
  initComponent: function() {
    Ext.apply(app.views, {
      contactsList: new app.views.ContactsList(),
      contactShow: new app.views.ContactShow(),
      contactEdit: new app.views.ContactEdit(),
      contactNew: new app.views.ContactNew(),
      contactCatalog: new app.views.ContactCatalog()
    });
    Ext.apply(this, {
      items: [
        app.views.contactsList,
        app.views.contactShow,
        app.views.contactEdit,
        app.views.contactNew,
        app.views.contactCatalog
      ]
    });
    app.views.Viewport.superclass.initComponent.apply(this, arguments);
  }
});

Update your index file (app/views/contacts/index.html.erb) to add the necessary imports.  Then you can run your application and you should see the empty ContactsList panel displayed.

<%= javascript_include_tag 'app/app' %>
<%= javascript_include_tag 'app/views/ContactCatalog' %>
<%= javascript_include_tag 'app/views/ContactEdit' %>
<%= javascript_include_tag 'app/views/ContactNew' %>
<%= javascript_include_tag 'app/views/ContactShow' %>
<%= javascript_include_tag 'app/views/ContactsList' %>
<%= javascript_include_tag 'app/views/Viewport' %>

Model: Contact.js

Now let’s take a look at the model. Create Contact.js in public/javascripts/app/models. Our model serves three purposes:

1. Get data from the web server for the application

2. Store data locally in localstorage

3. Post data to the web server that has been captured on the device.

We’re going to do this with multiple proxies.  The Sencha proxies make it easy to persist data.  The code below defines the fields, validations, and a proxy for saving a single model instance to the web server.  I like using xml to transmit back and forth but I notice that the Sencha guys like using json. XML is more comfortable for me at the moment and it seems to work well with ROR.

//Contact.js
app.models.Contact = new Ext.regModel('app.models.Contact', {
  fields: [
    {name: 'id', type: 'int'},
    {name: 'remote_id', type: 'int'},
    {name: 'synced', type: 'boolean'},
    {name: 'first_name', type: 'string'},
    {name: 'last_name', type: 'string'},
    {name: 'email', type: 'string'},
    {name: 'phone', type: 'string'}
  ],
  validations: [
    {type: 'presence', field: 'first_name'},
    {type: 'presence', field: 'last_name'}
  ],
  proxy: {
    type: 'ajax',
    url: 'contacts.xml',
    reader: {
      type: 'xml',
      record: 'contact'
    },
    writer: {
      type: 'xml',
      record: 'contact'
    }
  }
});
...

Now add two more stores to your model.  The first one is a local store which will help with CRUD to your local storage.  The second is a remote store that we use only to get a complete list of data from the web server to populate our catalog.

//Contact.js
...
app.stores.localContacts = new Ext.data.Store({
  id: 'localContacts',
  model: 'app.models.Contact',
  proxy: {
    type: 'localstorage',
    id: 'contacts'
  }
});

app.stores.remoteContacts = new Ext.data.Store({
  id: 'remoteContacts',
  model: 'app.models.Contact',
  proxy: {
    type: 'ajax',
    url: 'contacts.xml',
    reader: {
      type: 'xml',
      root: 'contacts',
      record: 'contact'
    },
    writer: {
      type: 'xml',
      record: 'contact'
    }
  }
});
...

Finally we need to add the CRUD and synchronizing code. The first function app.models.save is called from the controller when the save button is clicked on the ContactNew form.  This takes all of the data from the form and persists it into local storage using the local store.  The stores work really well with models so one trick that I use is to create a new model using the data from the form.  Ext.ModelMgr.create(data, modelname) makes it easy to pass in a list of name-value pairs to create a new model instance.  The store has a really nice method (add) for persisting existing models.  Together you can pull all of your form data and persist it with only a couple of lines of code.

// Contact.js
...
app.models.save = function() {
  var form = app.views.contactNew
  var params = form.getValues();
  var newcontact = Ext.ModelMgr.create(params, app.models.Contact);
  var errors = newcontact.validate();
  if (errors.isValid()) {
    app.stores.localContacts.add(newcontact);
    app.stores.localContacts.sync();
    form.reset();
    return true;
  } else {
    var errorMsg = '';
    errors.each(function(e) {
    errorMsg = errorMsg + fieldHumanize(e.field) + ' ' + e.message + "<br />";
    errorMsg = errorMsg ;
  });
  Ext.Msg.show({
    title: 'Error',
    msg: errorMsg,
    buttons: Ext.MessageBox.OK,
    fn: function() {
      return false;
    }
  });
}

Next we write the update function. This is called from the controller when the update button is clicked from the ContactEdit screen. All of the data is pulled from the form into a params variable.  The code then loops through the params and updates everything on the model.

...
app.models.update = function(id) {
  var contact = app.stores.localContacts.getById(id);
  if(contact) {
    var form = app.views.contactEdit
    var params = form.getValues();
    for(var field in params) {
      console.log("field: " + field + ' | value: ' + params[field]);
      contact.set(field, params[field]);
    }
    var errors = contact.validate();
    if(errors.isValid()) {
      contact.set('synced', false);
      app.stores.localContacts.sync()
      Ext.Msg.alert('Updated', 'The contact has been updated');
      return true;
    } else {
      var errorMsg = '';
      errors.each(function(e) {
      errorMsg = errorMsg + fieldHumanize(e.field) + ' ' + e.message + "<br />";
      errorMsg = errorMsg ;
    });
    Ext.Msg.alert('Error', errorMsg);
      return false;
    }
  } else {
    return false;
  }
}

Next a short delete function to remove the record from local storage only.

app.models.destroy = function(id) {
  var contact = app.stores.localContacts.getById(id);
  if(contact) {
    app.stores.localContacts.remove(contact);
    app.stores.localContacts.sync();
    return true;
  } else {
    return false;
  }
}

Finally the sync function. After validating that the device is online the localstore is loaded with the latest data from localstorage.  Each record in the local store is evaluated to find only those records that need to be synced (synced == false).  Once we have the sync array and there are more than 0 records in the syncArray we loop through it.  NOTE: I’m using a for loop but it is actually better to use an each loop when going through the array.  To do that you would replace for(var i=0….) with syncArray.each(function(form) {… existing code …}.  Then remove the line form = syncArray[i].

The pattern for syncing is as follows: use the data from the syncArray record to create a new model.  Then use the proxy on the app.models.Contact model to save the record to the web server.  This is why we have a proxy on the model, so that we can call syncModel.save and have the data synchronize with the server.  There are three callbacks: success, failure, and callback.  Success is called if the data successfully saves.  Failure is called if something goes wrong and Callback is called regardless of what happens.

One of the tricky things with Javascript and ExtJS is managing the asynchronous actions.  That is why the callbacks are used.  If you just call syncModel.save() and then try to pop a success message, it won’t work the way you think it would.  The save action will execute asynchronously and the code will move onto the next line while it the save is still executing.  So your alert message would display even though the save hadn’t finished.

app.models.synchronizeLocalToRemote = function () {
  if(!navigator.onLine) {
    Ext.Msg.alert('Offline', 'You need to be online to sync to the web server');
    return;
  }
  console.log('Start Sync');
  var localStore = app.stores.localContacts.load();
  var syncArray = getDataToSync(localStore);
  var count = syncArray.length;
  if(count == 0) {
    Ext.Msg.show({
      title: 'Synced',
      msg: 'All contacts are synced'
    });
    return;
  }
  var syncInfo = "";
  console.log("Number of items to sync: " + count);

  // Show the syncing spinner
  var mask = new Ext.LoadMask(Ext.getBody(), {msg: "Synchronizing"});
  mask.show();

  // Sync items to remote
  for(var i = 0; i < count; i++) {
    console.log("Index: " + i);
    form = syncArray[i];
    var syncModel = Ext.ModelMgr.create(form.data, app.models.Contact);
    // Calling save on the model calls the remote proxy
    syncModel.save({
      success: function(result, request) {
        var id = result.data['id']
        console.log("Result ID: " + id);
        console.log("Success");
        form.set('remote_id', id);
        form.set('synced', true);
        localStore.sync();
        syncInfo = 'Success: ' + form.get('first_name') + ' ' +
        form.get('last_name') + ' has been synced<br />';
      },
      failure: function(result, request) {
        console.log("Exception");
        console.log("Result: " + request.responseText);
        syncInfo = 'Failed: ' + form.get('first_name') + ' ' +
        form.get('last_name') + ' has been synced<br />';
      },
      callback: function(result, request) {
        console.log(syncInfo);
        if(i >= count - 1) {
          mask.hide();
          Ext.Msg.show({
            title: 'Complete',
            msg: syncInfo
          });
        }
      }
    });
  }
}

var getDataToSync = function(store) {
  var syncArray = new Array();
  store.each( function(form, index) {
    var isSynced = form.get('synced');
    if (!isSynced) {
      syncArray.push(form);
    }
  });
  return syncArray
}

Phew! Are you still with me? The code for the views is relatively straight-forward. I’ve posted the source code on GitHub so you can get walk through the views (public/javascripts/app/views) there.  However I want to walk through a couple of examples of following a click from the view through the controller to another view.

Views and Controller: contacts.js

Here is a snippet from ContactsList.js.  This is the button and handler for the “new” button on the top toolbar.  When you click on the ‘new’ button on the toolbar the framework will take you to the controller.

//ContactsList.js
...
{
  text: 'new',
  ui: 'confirm',
  handler: function() {
    Ext.dispatch({
      controller: app.controllers.contacts,
      action: 'newContact',
      animation: {type: 'slide', direction: 'left'}
    });
  }
}
...

The controller is in public/javascripts/app/controllers and is called contacts.js. From the newContact action in the controller we can see that the controller is setting the active panel on the viewport to the contactNew panel. One thing to note: it is setting the active panel to an instance of the new panel.  Notice the lower-case “c” on contactNew.  We are using the instances of the panels that were created in the Viewport code.

...
newContact: function(options) {
 app.views.viewport.setActiveItem(app.views.contactNew, options.animation);
},
...

A more complex example of moving from panel to panel involves selecting an item from the list. From the ContactList panel you can click on an item to edit it.  There are two click handlers:  onItemDisclosure handles clicks directly on the arrow and onItemTap handles clicks on the row.  They both do the exact same thing except that onItemDisclosure has access to the actual records whereas onItemTap has to translate the record from the item.  The code below should look familiar as compared to the code above with one significant addition: We are sending an id to the controller.  The id and the animation are both transmitted to the controller in an ‘options’ object.

//ContactsList.js
...
onItemTap: function(item) {
  record = this.getRecord(item);
  Ext.dispatch({
    controller: app.controllers.contacts,
    action: 'show',
    id: record.getId(),
    animation: {type: 'slide', direction: 'left'}
  });
}
...

The controller uses the id from the options hash to retrieve the correct record for editing.  If a contact is found in localstorage then the contactEdit view is updated with the data.  The panel is updated by calling a method in the contactEdit view called updateWithRecord

// contacts.js
...
edit: function(options) {
  var id = parseInt(options.id);
  var contact = app.stores.localContacts.getById(id);
  if(contact) {
    app.views.contactEdit.updateWithRecord(contact);
    app.views.viewport.setActiveItem(app.views.contactEdit, options.animation);
  }
},
...

It is a little bit magical actually. As long as you are using a FormPanel it is really easy to update the fields with data from an existing record.  By calling the ‘load’ method (this.load(record)) on the FormPanel and passing it the record each of the fields is mapped to the record object using the ‘name’ of the field.  For example if the first_name of the record is populated it will automatically fill in the textfield where name: ‘first_name’.  It will do this for all fields where the name equals the field from the record.  It is good to keep this in mind when designing your forms: Make sure to name your fields that same as your model fields.

// ContactEdit.js
...
updateWithRecord: function(record) {
  this.load(record);
  var topToolbar = this.getDockedItems()[0];
  topToolbar.getComponent('cancel').record = record;

  var bottomToolbar = this.getDockedItems()[1];
  bottomToolbar.getComponent('save').record = record;
  bottomToolbar.getComponent('save').form = this;
}

Make sure to add references to the controller and model in your index.html.erb.  Take care to add them in the following order. The Sencha framework will throw an error if the data for the ContactList is not available when you try to display the list. So it is important to load the model first, then the views.

<%= javascript_include_tag 'app/app' %>
<%= javascript_include_tag 'app/util' %>
<%= javascript_include_tag 'app/models/Contact' %>
<%= javascript_include_tag 'app/views/ContactCatalog' %>
<%= javascript_include_tag 'app/views/ContactEdit' %>
<%= javascript_include_tag 'app/views/ContactNew' %>
<%= javascript_include_tag 'app/views/ContactShow' %>
<%= javascript_include_tag 'app/views/ContactsList' %>
<%= javascript_include_tag 'app/views/Viewport' %>
<%= javascript_include_tag 'app/controllers/contacts' %>

That is pretty much it for our application.  There are some fun things in the source code, like a catalog where you can view a list of items from the server on your mobile device.  Then touch the item to download it to the device for manipulation.  Please post any questions or comments and I’ll try to help out.

Thanks for reading!

Sencha Touch application with Ruby on Rails – Part 1

Hi,

As promised I’m back with an example application written in Ruby on Rails and Javascript built on the Sencha Touch framework.  This is a Contacts application with a “checkout” functionality.  I’ve had to split it into two blog posts due to size. This is what we are trying accomplish:

  • Add a new contact via the Web interface or via the device (pad, phone) interface
  • Contacts that have been added on the device are stored in local storage
  • Pressing “Sync” on the device will push unsync’ed data from the device to the web storage
  • List all contacts that are stored locally on the phone
  • List all contacts that are stored on the server in the “Catalog”
  • Upon clicking an entry in the Catalog it is checked out to your local storage

Here are some screen shots of the final product – Yellow contacts are un-synced.  Catalog not shown.

Let’s get started

Side Note: I recommend using Safari for development of Sencha Touch applications. Safari’s Develop menu gives it an advantage over other browsers in my opinion.  Although I’ve heard Chrome is quite good as well:

  1. If you do not see a Develop menu at the top of the screen between Bookmarks and Window go to Preferences (Edit/Preferences on Win, Safari/Preferences on Mac).  From the Preferences menu select Advanced.  From the Advanced page select “Show Develop menu in menu bar”
  2. From Develop/User Agent you can view the site as if you are viewing it from a mobile device.  I’m not sure if other browsers have this but it is a killer feature
  3. From Develop/Show Web Inspector you can view a very nice debugger panel.  The Web Inspector panel provides a tab that displays the local storage.  It also provides a console tab where you can type in JavaScript command and test code against you application. This has proved to be invaluable when trying to debug the Sencha Touch application.

Rails Application

Create the Rails Application

First thing, create your Rails app. The Ruby On Rails server app in this example is minimal.  It was created as a scaffold and the controller has been customized to handle the xml going back and forth. From the command line the following will create your Rails application and database.

$ rails new contacts
$ cd contacts
$ rails g scaffold contact first_name:string last_name:string email:string phone:string
$ rake db:migrate
$ rails s

Navigate to http://localhost:3000.  You should see the rails welcome page.  Next we’re going to update routes.rb so that the root points to your index page for your contacts.  First delete the index.html page in the public directory. Then update config/routes.rb to set the root to contacts/index.

ContactsDemo::Application.routes.draw do
  root :to => 'contacts#index'
  resources :contacts
end

Update the Controller

Open up app/controllers/contacts_controllers.rb. The controller needs to be updated so that it plays nicely with your Sencha Touch app. There are two things you’re trying to do with the Rails code:

  1. Update the index so it delivers an xml list of your contacts
  2. Update the create so that new contacts are created or updated accordingly.  NOTE: This is a very high-level approach to synchronizing records between two data sources. If you are familiar with Version Control (Subversion and Git) then you have seen synchronization done at a very deep level. This application will not check at the field level for collisions or anything on that order. Simply put: The application will treat any incoming record as the latest and will update the online DB with the entire record.

Index (Update: add dasherize => false. This will make your xml send first_name rather than first-name)

def index
  @contacts = Contact.all
  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render : xml => @contacts, :dasherize => false }
                # Note: WordPress workaround: do not put a space between the colon and xml
                # WordPress was doing funny things with colonxml so I had to put a space
  end
end

Add 3 new methods to the end of the controller: parse_sencha_xml, update_record, and parse_contact_params

def parse_sencha_xml
  p_hash = params[:xmlData][:contact]
  return nil if p_hash.nil? || p_hash.empty?
  # call update if the remote_id is populated, means it's already in the db
  if p_hash['remote_id'].to_i > 0
    return update_record(p_hash)
  end
  contact = Contact.create!(parse_contact_params(p_hash))
  return contact
end

def update_record(p_hash)
  id = params[:xmlData][:contact]['remote_id']
  c = Contact.find(id)
  update_params = parse_contact_params(p_hash)
  c.update_attributes(update_params)
  return c
end

def parse_contact_params(p_hash)
  contact_hash = Hash.new
  attr = Contact.new.attributes
  p_hash.each do |key, value|
    if (key == 'id' || key == 'remote_id' )
    # skip, this is the device PK or the db PK.  The db PK has already been captured
    elsif attr.has_key?(key)
      contact_hash[key] = value
    end
  end
  return contact_hash
end

Finally, update the Create method to use the new methods. It will now look for matching records before adding a new record. If it finds one, it will update it.  Update create so that it calls the new methods

def create
  respond_to do |format|
    format.html {
      @contact = Contact.new(params[:contact])
      if @contact.save
        redirect_to root_path
      else
        render :action => 'new'
      end
    }
    format.xml {
      @contact = parse_sencha_xml
      render : xml => @contact, :status => :created, :dasherize => false
             # Note: WordPress workaround: do not put a space between the colon and xml
# WordPress was doing funny things with colonxml so I had to put a space
    }
  end
end

Routing and viewing both Mobile and Standard sites

Now that our controller is updated there are a few things we need to do to take care of routing and add the ability to view mobile or standard sites.

Update app/controller/application_controller to allow for mobile or standard display. The following is pulled directly from Railscasts episode 199. Rails will evaluate the user_agent from the incoming request and true if it contains “Mobile” (Android or iOS) or “webOS” (Palm)

class ApplicationController < ActionController::Base
  helper :all
  protect_from_forgery

  private
    def mobile_device?
      user_agent = request.user_agent
      user_agent =~ /Mobile|webOS/
    end
    helper_method :mobile_device?

end

Update the view so that the page displays in a browser. First update the index page.  The new mobile_device? method is used to determine which part of the index page to display.

<% if(mobile_device?) %>

 <!-- Code Viewable to mobile devices -->
 <%= content_for :head do %>
 <%= stylesheet_link_tag 'sencha-touch-debug' %>
 <%= javascript_include_tag 'touch_1_0_1/sencha-touch-debug' %>

 <%= javascript_include_tag 'app/app' %>
 <%= javascript_include_tag 'app/util' %>
 <%= javascript_include_tag 'app/models/Contact' %>
 <%= javascript_include_tag 'app/views/ContactCatalog' %>
 <%= javascript_include_tag 'app/views/ContactEdit' %>
 <%= javascript_include_tag 'app/views/ContactNew' %>
 <%= javascript_include_tag 'app/views/ContactShow' %>
 <%= javascript_include_tag 'app/views/ContactsList' %>
 <%= javascript_include_tag 'app/views/Viewport' %>
 <%= javascript_include_tag 'app/controllers/contacts' %>

 <style>
 .synced {
 background-color: #EDE613;
 }
 </style>

 <% end %>

<% else %>
 <%= content_for :head do %>
 <%= stylesheet_link_tag 'scaffold' %>
 <%= javascript_include_tag :defaults %>
 <% end %>

 <!--Add code from index.html.erb -->
 ...

<% end %>

Next update app/views/layouts/application.html.erb to remove a couple of lines that you don’t need for mobile browsers

<!DOCTYPE html>
<html>
<head>
 <title>ContactsDemo</title>
 <%= csrf_meta_tag %>
 <%= yield :head %>
</head>
<body>

<%= yield %>

</body>
</html>

That’s it for the rails application. When you view the page in a standard browser you should see the index page that lists all of your contacts.  If you change the User Agent (Safari) to Mobile Safari 4.1 you will see a blank gray screen. If something appears to explode when you switch to Mobile Safari remove the javascript imports that start with ‘app/… I can’t remember if Safari gets made if you ask it to import something that is not there. I will be posting the Sencha Touch application next time.

Thanks for reading!

References:

Excellent MVC Tutorial with Sencha Touch and PhoneGap

Railscasts episodes 199, 247, and 248 – by Ryan Bates.  Totally amazing gift of time, energy, and knowledge from Ryan, an absolute must watch for Rails developers.  If you want to do it in Rails, Ryan has probably already done it and has a nice succinct video that explains it to you.

Mobile Apps: Native v Web-based

I’m getting into development for mobile devices specifically iOS and Android devices. The first thing a developer needs to ask themselves when going down this road is: What language am I going to use? From the time that the iPhone came out up until recently (Fall 2010) the answer was easy. If you wanted to give your users the best experience, you went native. Whether it be iOS or Android: Native was the only way to develop a decent app.

However 3 recent developments have changed the game: 1) HTML5, 2) The introduction of version 1.0 of the Sencha Touch framework, and 3) Major performance increases in WebKit and Google V8 based browsers.  When you combine these technology introductions/improvements with the improvement in wrapper technologies like PhoneGap and Titanium from Appcelerator and we now have real alternatives when it comes to developing applications for Mobile devices. Even venerated application design shops like 37Signals have switched over to Web-based applications for mobile.

The benefits are obvious and many others have written very nice articles explaining the differences and pros/cons (One of my favs).  However here is my two cents (after all, that’s why you’re here). Write Once/Deploy Anywhere is great and no app stores is great but to me the primary benefit is Fun!  I’m a Java programmer in my day job, and it’s a great language for paying the bills.  But it is not a fun language for coding.

Full disclosure: My Android programming experience amounts to coding along with some tutorials… And it sucked!  Writing XML is horrible and coding esoteric handlers in Java with inner classes to handle behavior and UI rendering is non-intuitive at its best and absolutely confusing and non-understandable at its worst.  After one day I was so sick of writing android:blah blah blah.  I’ve coded Windows Mobile apps in C# with the same feelings.  It is not fun at all.  These languages are great as powerhouse engines in IT back rooms but they are not great for Consumer facing UI design.

Contrast that with the Sencha Touch framework where within a couple hundreds lines of code you can have a beautiful UI complete WITH connectivity to a Web-based data store that runs on iOS and Android and there’s no comparison.  Now that the supporting technologies (HTML5 and WebKit) are catching up it’s wonderful to have real alternatives.

In my next post I’ll walk through a Sencha Touch application with a Ruby on Rails backend.  It is a simple contacts application that stores data locally and syncronizes to a Rails Web Store.  Check back soon…

Thanks for reading

Sencha, Rails3, Forms, and the authenticity token

I’m playing with Sencha Touch right now in a Rails app.  One of the things that hung me up for a bit was the authenticity token that is required with POSTing form data to the rails controller.  Here is how I did it.

In the Sencha file where you declare your FormPanel capture the Rails csrf_token as a variable by adding the following:
var csrf_token = document.getElementsByName("csrf-token")[0].getAttribute("content");
In your FormPanel create a hidden field to submit the token to the controller
items: [
{
xtype: 'hiddenfield',
name: 'authenticity_token',
value: csrf_token
},
... more items ]

Now when you submit the form your authenticity token will be submitted and you can keep the cross-site-scripting forgery protection that Rails provides

Excellent Reference Materials

I have recently encountered two excellent resources:

1). Michael Hartl’s tutorial on Rails3.  This is an excellent overview of Rails3, Test Driven Development, and the most popular tools for developing applications in Ruby on Rails.  This tutorial is really for anyone that is involved with producing applications for the Internet.  If you are a graphic designer it will help you learn to start adding database functionality to your sites.  If you are a developer the tutorial will introduce you to the best language/framework available for creating web-based applications (Ruby on Rails).  And if you already know Ruby On Rails the tutorial is truly like “looking over the shoulder of an expert RoR programmer” as the quotes claim.  Fantastic and well worth the $95 for book and videos.

2). The Intelligent Entrepreneur by Bill Murphy Jr. I came across this book accidentally when my wife brought it home from the library for herself.  I picked it up and started reading and couldn’t put it down. The title of the book sounds stuffy and the quotes don’t make it seem like it is going to be an inspiring read but this is an excellent book for anybody that has entrepreneurial dreams.  The stories are inspiring and show you 3 ways in which businesses can be started.  They also form an anecdotal account of the business climate of the late 90’s early 00’s, most notably the Internet boom and collapse.  It is fascinating to read about actual entrepreneurs dealing with the challenges of that time.

One particular line prompted me to write this blog post.  On the second to last page of the book he refers to a book written by a Harvard Business School professor that tries to “show readers how to juggle … the four key elements in work and life: happiness, achievement, significance, and legacy.” That line nailed it for me for that is exactly what what I’m searching for.  I have asked myself the question often: Why do I want to run my own business? I have a great life with a well-paying job and low stress. After reading that line I realized that I only have 1 of the 4 (happiness). I want them all. In my opinion those four factors define complete self-fulfillment.