Heroku is a pioneer in what we now call Platform-As-A-Service. It’s a little on the expensive side to scale on it, but its great for developing with as there is a freebie tier and its service makes deploying to the internet a breeze. Be aware however that if you need a database, PostgreSQL is your only option.
The newcomer in town is Appfog. They’re a lot cheaper than Heroku and supports MySQL in addition to PostgreSQL, but I haven’t had the chance to check them out yet.
In the root folder of your application, type in the following commands
12345678910111213141516171819202122232425
# Initialize a git repositorygit init
# Login to heroku (enter your username and password as prompted, generate ssh key if required)heroku login
# Create a new app on heroku# Make note of the output of this command# The http url is where your application will be available - http://<app name>.heroku.com# The git url is where you will be deploying the application to - git://heroku.com:<app name>.git# The last line should say 'Git remote heroku added'# If it doesn't, do 'heroku git:remote -a <app name>'heroku create
# Add everything to git staginggit add .
# Commit the repositorygit commit -m "initial commit"# Push to Heroku for the first timegit push heroku master
# Ensure that only 1 web dyno will be runningheroku ps:scale web=1
Step 4
Your app should now be available in the http url mentioned in step 3. If there are any problems, you can watch your application’s live logging by using heroku logs -t. As usual, google your issues :) There are some relevant links to documentation below too.
Since Twitter open sourced their CSS framework several years ago, Bootstrap has become the benchmark for CSS. As a terrible designer, I’ve very much relied on Bootstrap to make my web pages decent looking, not great – just OK.
I’ve opted for a slightly older version (2.3.2) here since the new version 3 is not yet stable at the time of writing. The documentation for 2.3.2 can be found here. Regardless, there’s only 3 files to change.
As I mentioned in the very first post, Rails has been credited with Ruby’s sudden, meteoric rise in popularity. It’s not the only web application framework for Ruby, but it remains by far the most popular to this day. If you’re interested in a career in web development and want to stay away from corporate enterprises, this is a great way to go about it.
Rails emphasises the Model-View-Controller principle, and if you’re not familiar with the concept, it’s essentially the separation of the data, to the logic of processing the data, and the display of the processed results (links at the bottom for more details). The application I’ll be demoing will ignore the Model part however. This is a very simple application will retrieve some data from Twitter, same as the previous post, and display it on a webpage.
As always, start by installing it…gem install rails
Scaffolding
One of the big features of rails is scaffolding – automatically generating common parts of an application. This is the first step of development. Here, we’re asking rails to scaffold the project without support for a database.
123
cd ~
rails new twitter_app -O
cd twitter_app
The rails generator has created a lot of new files – about 20 in fact – but there aren’t that many we need to worry about.
Before you begin editing the files, copy the twitter configuration file from the previous pages to the config/initializers directory. Files in this directory are run when the server is started.
Gemfile
This file basically tells the Ruby environment what gems are required to run the the application. Our app only needs the twitter gem so just add that.
Source specifies where it should look for the gems if they were to be installed. We can also specify the version of a gem we want in order to ensure that things work as we expect; don’t want updates to break the application. Everything else in the file is optional.
The Twitter controller
Finally on to the logic… rails generate controller twitter.
The code here is almost identical to that from the previous Twitter post. Now, we’re just keeping all the tweets in an array instead of just printing it. At the end of the processing, Rails will automatically look for the template views/<controller name>/<function name>.* unless you specify which HTML template to use with the render. This is displayed within views/layouts/application.html.erb.
The first line in the block points the root path, / to the proposals function in the twitter controller. The second and third points /proposals and /ausvotes paths to their respective functions in the same controller.
Justin Bieber Proposals page
If you’re familiar with JSP, this is very much the same – HTML mixed in with some code. Here, we’re making a simple table but we’re creating a row for each tweet.
app/views/twitter/proposals.html.erb
1234567891011121314
<h1>Last 200 Justin Bieber Proposals</h1><table><tr><th>User</th><th>Text</th></tr><% @tweets.each do |tweet| %>
<tr><td><%= tweet.user.name %></td><td><%= tweet.text %></td></tr><% end %>
</table>
#ausvotes page
Identical to the above. Do try to refactor this :)
app/views/twitter/ausvotes.html.erb
1234567891011121314
<h1>Last 200 Tweets with #ausvotes</h1><table><tr><th>User</th><th>Text</th></tr><% @tweets.each do |tweet| %>
<tr><td><%= tweet.user.name %></td><td><%= tweet.text %></td></tr><% end %>
</table>
Deploying with WEBrick
WEBrick is a very simple Rails web server, perfect for dev testing. Just go to the root directory of the application and type in rails server. WEBrick listens to port 3000 by default, but look carefully at its output if you come across any problems. The JB Proposals page will be available in @ http://0.0.0.0:3000 and http://0.0.0.0:3000/proposals while the #ausvotes page will be available at http://0.0.0.0:3000/ausvotes.
12345678
$ rails server=> Booting WEBrick=> Rails 4.0.0 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h`for more startup options=> Ctrl-C to shutdown server
[2013-08-05 22:13:15] INFO WEBrick 1.3.1
[2013-08-05 22:13:15] INFO ruby 2.0.0 (2013-06-27)[x86_64-darwin12.4.0][2013-08-05 22:13:15] INFO WEBrick::HTTPServer#start: pid=25428 port=3000
Adding links between the 2 pages
We want the user to be able to easily manuever between the 2 pages so let’s put hyperlinks to the 2 pages at the top of every page (just add the 2 anchor bits in the html below).
Just refresh the page to take affect. Notice that this change did not require you to restart WEBrick. Some changes, eg. config changes, will require you to do so.
Since mid June this year, Twitter has forced users to use OAuth to authenticate and access its API. You can no longer access its data in a trivial way like the GitHub example before. You must get 4 keys from Twitter’s developer page: Consumer key, Consumer secret, Access token and Access secret – don’t need to know what they mean yet, but be sure that the 2 secret keys are not shared. OAuth is a real pain. These 4 keys won’t give you access. They’ll let you get 3 more one use keys which you can then use to access the API.
Fortunately for you as a Ruby user, there are two libraries that will do all the menial work for you. Twitter is a conveniently named library to access the standard Twitter API (it is not developed by Twitter Inc) while the other, TweetStream is designed to use Twitter’s streaming API (kind of like email pushing on your phone). It’s unlikely that you’ll need to use the streaming API for this assignment so I won’t be showing you TweetStream.
Twitter Gem
Install the twitter gem with gem install twitter and make the following config file, replacing the upper case strings with the relevant keys.
Just to give another example, I’m going to get the last tweet from each of the users I’m stalking.
1234567891011121314151617181920212223242526
f=Twitter.friendsf.class# Twitter::Cursor# -- http://rdoc.info/gems/twitter/Twitter/Cursorf.collection.class# Arrayf.collection[0].class# Twitter::User# -- http://rdoc.info/gems/twitter/Twitter/Userf.collection[0].name# "John Oliver"f.collection[0].statusf.collection[0].status.class# Twitter::Tweet# -- http://rdoc.info/gems/twitter/Twitter/Tweetf.collection[0].status.text# "Mugabe is the Harlem Globetrotters of democracy. His winning record is undeniably impressive, but he doesn't really play by the rules."foruserinf.collection.eachputs"#{user.name} said '#{user.status.text}'"end
Because we don’t care about the return value, let’s not do this in irb
last_twitter_status.rb
12345678
#!/usr/bin/env rubyrequire'twitter'load'twitter_config.rb'f=Twitter.friendsforuserinf.collection.eachputs"#{user.name} said '#{user.status.text}'"end
But there’s still a problem, I’m following more users than this.
This is because Twitter paginates the results to 20 by default. So if there is more than 20 records, you’ll have to iterate through each page to get all the results.
last_twitter_status_iterated.rb
123456789101112
#!/usr/bin/env rubyrequire'twitter'load'twitter_config.rb'cursor=-1whilecursor!=0dof=Twitter.friends:cursor=>cursorforuserinf.collection.eachputs"#{user.name} said '#{user.status.text}'"endcursor=f.next_cursorend
Just to a more relevant example, this is to get the last 200 tweets with #ausvotes excluding retweets. Search results pagination work slightly different to friends – refer to documentation!!
Note that the count parameter refers to the number you want per page, although the maximum is 100.
recent_ausvotes.rb
123456789101112
#!/usr/bin/env rubyrequire'twitter'load'twitter_config.rb'max_id=-1foriin(0..1)t=Twitter.search("#ausvotes -rt",:count=>100,:result_type=>"recent",:max_id=>max_id)t.statuses.eachdo|tweet|puts"#{tweet.user.name} said #{tweet.text}"endmax_id=t.next_results[:max_id]end
As you saw in the previous post, XML is an overly verbose format so in the last few years, what we call JSON (JavaScript Object Notation) has come to dominate web communication. Ideally I’d be demonstrating this with Twitter’s API since you’re likely to use it for this assignment, but since mid June this year, the Twitter API requires OAuth to access. I will be address this in the next post.
If you’ve been writing Javascript, you love JSON. If you haven’t, you soon will. The following is a sample of a JSON formatted file. Note that spaces, tabs and line breaks are all optional. I’ve just added those to make it easier to read.
That’s all there is to JSON, very simple, very clear. {} encapsulates object/map/hash, while [] encapsulates an array, both of which can be nested infinitely. Otherwise only strings, numbers, booleans and null are supported values.
Github API
GitHub is an online source repository, extremely popular with open source projects. You won’t be using any data from it for your projects, but it’s the first public JSON API that came across my mind. I’m sure you’ll be using it somewhere in your career though. For this demonstration, I’ll just be using the most simple of calls, retrieving the details of the GitHub user octocat. The documentation for GitHub’s API is available here.
The easiest way to access this data, is to simply open a web browser and go to https://api.github.com/users/octocat. Next step further is accessing it through cURL.. curl https://api.github.com/users/octocat. Let’s do it in Ruby.
Retrieving with Net/HTTP and parsing with json
Net/HTTP is a standard Ruby library, and it’ll be your interface to the internet. JSON is a simple parser and it’s also a standard library.
For the purpose of this exercise, I’ve downloaded and extracted a zip file from the AEC’s site wget wreckbea.ch/aec-mediafeed-results-standard-light-15508.xml Ruby has an XML parser called REXML in its standard library, but it’s known to be very slow – Some 50 times slower than Nokogiri. I would love to demonstrate Nokogiri, but unfortunately it’s more complex to use than XmlSimple. XmlSimple parses the data into a native Ruby hash whereas Nokogiri has its own set of classes.
Third Party libraries
Third party libraries in Ruby are referred to as gems. Gem is an executable that comes with Ruby. Tell it to install, along with the name of the gem and it will download and install the gem that you want as well as all its dependencies…gem install xml-simple
Parsing XML takes a little while, and XmlSimple isn’t the most efficient of parsers. If speed is a concern at all, you should definitely look into Nokogiri.
Once it’s done we can see what’s in there one step at a time.
Ruby is a Object Oriented language so it’s no less than intuitive to have classes. The following code block shows the basic syntax of a Ruby class.
1234567891011121314151617181920
classCounter@@classCount=0@instanceCountdefinitialize(startInstanceCount)@instanceCount=startInstanceCountenddeficIncrement@instanceCount+=1enddefself.ccIncrement@@classCount+=1enddefto_s"classCount = #{@@classCount} and instanceCount = #{@instanceCount}"endend
We have a Class variable, @@classCount. This is equivalent to the keyword static in Java. There’s an Instance variable @instanceCount.
Then there are the methods. initialize is the constructor used when you run Counter.new, icIncrement is an instance method, while self.ccIncrement is a class method – called with Counter.ccIncrement.
Finally to_s is the conversion of the class to a String, just like toString().
123456789101112
a=Counter.new0b=Counter.new0Counter.ccIncrementa.icIncrementputsa# classCount = 1 and instanceCount = 0b=Counter.new5putsb# classCount = 1 and instanceCount = 5
Variable Scope
Scope-wise, there are 5 different types of variables in Ruby and they are simply differentiated by the first character of their name.
$: Global
@@: Class
@: Instance
[A-Z]: Constant
[a-z_]: Local
Note that Constants can still be changed. The interpreter will simply issue a warning that that is the case, but the value assigning will proceed.
12345
Aconstant=1Aconstant=2# warning: already initialized constant Aconstant# warning: previous definition of Aconstant was here# 2
Dynamic Typing
Ruby doesn’t care what class an object is, as long as it does what you want it to do. If it quacks like a duck, it is a duck.
I’ve prepared the 3 files below already. To see them, checkout the branch git checkout dynamic_typing. This code is based on the code snippets in the Ruby Cookbook which was based on Ruby 1.8
require'duck'require'humans'require'make_it_quack'd=Duck.newm=Man.neww=Woman.newmake_it_quack(d)# Quack!make_it_quack(m)# Moo!make_it_quack(w)# NoMethodError: undefined method `quack' for #<Woman:0x007fb2d91ab3d0>
Unfortunately it seems like function parameters can no longer be given a type so the example isn’t the most clear. This is what it looks like in the book.
1234567
defmake_it_quack(Duckduck)putsduck.quackendw=Woman.newmake_it_quack(w)# TypeException: object not of type Duck
Duck Punching
So what if our ducks (Man) don’t quack? Then we punch them until it does.
Firstly the syntax. Let’s first define a very basic function we can use for this post.
12345678
defprint_stuff(str1,str2,reverse=false)ifreverseputs"#{str2} and #{str1} received!"elseputs"#{str1} and #{str2} received!"endstr=str1+str2end
Calling functions
Brackets around function parameters is optional in Ruby. However, sometimes it’s useful to include them regardless for clarity’s sake.
12345
print_stuff("First argument","Second argument")# First argument and Second argument received!print_stuff"First argument","Second argument"# First argument and Second argument received!
Arguments can be made optional by giving them a default value.
12345
print_stuff("First argument","Second argument",false)# First argument and Second argument received!print_stuff("First argument","Second argument",true)# Second argument and First argument received!
Return value
As you may have already noticed, print_stuff does use return even though it does exist in Ruby and it does exactly what you’d expect. If the return value is not specified, Ruby will return the value returned in the last executed line of the block
Because print "add successful" returns nil, add_print returns nil.
Error Handling
1234567891011121314
defdo_somethingraise"Failed to do something"enddo_something# RuntimeError: Failed to do somethingbegindo_somethingputs"Done something"rescueputs"Rescuing from exception"end# Rescuing from exception
retry will return the cursor to start of the begin block it belongs to
1234567891011121314
i=0beginputs"#{i}"i+=1ifi<2do_somethingendputs"All done!"rescueretryend# 0# 1# All done!
a.each{|k,v|puts"The value for #{k} is #{v}"}# The value for a is b# The value for 3 is d# The value for 5 is a.each_key{|k|puts"The value for #{k} is #{a[k]}"}# The value for a is b# The value for 3 is d# The value for 5 is 6a.each_value{|v|putsv}# b# d# 6a.eachdo|k,v|puts"The value for #{k} is #{v}"end# The value for a is b# The value for 3 is d# The value for 5 is 6
Symbols
Fixnum always have the same object_id, and we can tell Ruby to do that to Strings too – it’s what we call a Symbol. While a new string will be created every time the same String literal is used, the same symbol will always point to the same object in memory. This also means that Ruby’s automatic garbage collection will not recycle symbols.
Like the if statements you saw 2 posts prior, there are many ways to construct loops. Not that there is no increment/decrement, ++/--, operation in Ruby.
There’s also 4 keywords to help you manage the control of flow break, next, redo and finally retry which I’ll bring up in the Error Handling section. break exits the inner most loop
12345678
foriin0..2putsiifi==1breakendend# 0# 1
While next jumps to the next iteration of the loop