Tuesday, December 22, 2009

Rails: How to return to a previous page



Problem: In my Stock Market Investing Game smig.servegame.com I can "buy" a stock from either the user's screen, or stock listing screen, or individual stock show screen. Clicking the "buy" button sends me to a "buy" stock screen. After a purchase is complete, I would like to return the user to wherever they started the "buy".

Solution: Store the return url in the session hash.

First, save the current URL in users_controller.rb "show" action, as well as the stocks_controller.rb "index" and "buy" actions, with this code:
session[:stock_buy_return] = request.request_uri
Note the "uri" at the end of "request.request_uri". In older Rails versions it was url.

Second, in the stocks_controller.rb, in the dopurchase action (which completes a buy) add this code to return to the saved url:

redirect_to(session[:stock_buy_return] || stocks_url)
session[:stock_buy_return] = nil


That's it!

Saturday, October 17, 2009

Rails: How to sort the index view


Rails makes it delightfully easy to display the index view in sorted order.

All you have to do is load up the data in sorted order.

In my case I go to the stocks_controller.rb file and edit the index action.

The first line is: @stocks = Stock.all

I just replace it with:

@stocks = Stock.find(:all, :order => 'symbol')

Done!

How to add an index to a Rails table

Situation: I realize that there will be lots of stocks and my application will need to find and list them by symbol alphabetical order.

Solution: Use a migration to add an index.

I use script/generate migration symbol_index to create an empty migration.
Then I go to db/migrations and edit the latest migration file to:

class symbol_index < ActiveRecord::Migration
def self.up
add_index :stocks, :symbol
end

def self.down
remove_index :stocks, :symbol
end
end


The remove_index is needed so if later, I backup the version, it will delete the index (then when I migrate forward the index will be added back).

Finally:

$ rake db:migrate


to make the db update happen. You can read more in the Rails documentation.

How to get a web page (using sockets)


Situation: I want my program to automatically update the price of a stock. This information is available on another web page. How do I get that data?

It took some hunting, but I eventually found how to do this at TutorialsPoint.com in an article about Ruby socket programming.

The code:

require 'net/http'

@stock = Stock.find(params[:id])
url = '/api/Quotes/Realtime/' + @stock.symbol
resource = Net::HTTP.new("judstephenson.com", 80)
headers,pagedata = resource.get(url)


For the stock symbol AA (Alcoa Aluminum) you get:
AA NYSE 14.04 -0.32 -2.23 14.28 15.11 14.00 4.97

It's that easy!

Saturday, October 10, 2009

How to generate a migration adding a column to a table.


As we develop and evolve a Rails application we may need to add fields to a table.

These are handled via Rails migrations. The Rails documentaiton on migrations explains how to create migrations and what they can do.

Use the generate command to create a new (empty) migration.
$ script/generate migration MyNewMigration

There is a very handy shortcut when adding a field to a table

$ script/generate migration add_fieldname_to_tablename fieldname:string

A page listing generators has a more advanced example:

$ ./script/generate migration AddTitleBodyToPost title:string body:text published:boolean`
Note: When generating a whole new table, it's a good idea to use the scaffold command as shown in a recent blog. Or if you just want the table, but not the scaffold (controller, view) you can generate just the model:
$ ./script/generate model post title:string body:text published:boolean
Of course, whenever we've generated migrations, we need to finalize with:

$ rake db:migrate



How to create a table with Rails generate scaffold


Rails makes it exceptionally easy to create a new table. In SMIG, my Stock Market Investment Game, I will need a table with stocks.

What do I want to know about each stock? Let's think of a specific stock, say Portland General Electric Company - the folks that bring me electricity. I want to know the trading symbol (POR), a description that tells me what stock this is (Portland General Electic), and the current price.

Eventually I'll need a way to get prices in real time, but initially I'll just store them in the database. I want to have a timestamp for the price in the database (so I will know how old it is and when to update the price). Maybe I will need to know what exchange (NYSE, NASDAQ, etc) the stock trades on. Also, I should give players a way to find out more about a stock, so I'll include a URL to more information about the stock.

There are only a limited number of stock exchanges, so I will eventually want to have a table listing the exchanges. For now, I'll just have an integer that will be an index into the Exchange table.

The following command creates a database table entry for the Stocks table:
$ script/generate scaffold stock symbol:string description:string exchange_id:string price:float pricestamp:timestamp url:string
Every time I make additions to the database, I also need to migrate up to the latest version of the database.
$ rake db:migrate
Scaffold does a lot more than just create the database table for Stocks. It also creates app/controllers/stocks_controllers.rb file and app/views/stocks directory with initial scaffold code to list, view, create, update and delete stocks!

I can access this initial code by browsing to http://localhost:3000/stocks.

Initially the list will be empty, but there is a "New Stock" link at the bottom. Clicking on that link gives me the create new stock window, shown above.

Later on I might forget the names and types of the fields I created. I could go to MySQL and look at the fields in the table. Or, I could go to smig/db/migrate and find 20090929235716_create_stocks.rb file. There I will see:

class CreateStocks < ActiveRecord::Migration
def self.up
create_table :stocks do |t|
t.string :symbol
t.string :description
t.integer :exchange_id
t.float :price
t.timestamp :pricestamp
t.string :url

t.timestamps
end
end

def self.down
drop_table :stocks
end
end

Monday, October 5, 2009

How to use Rails with MySQL

I want to develop a web based game that I hope will eventually have thousands of users. Rails defaults to SQLite a single file "server-less" database. I believe performance of my game will be much better if I use MySQL.

How to do it?

Get Ready
  • You need Ruby and Rails installed on your system. Installation varies depending on your system.
In my case I'm running Ubuntu and I mostly followed the instructions at: http://wiki.rubyonrails.org/getting-started/installation/linux-ubuntu
  • You may need to install MySQL support for Ruby.
In my case I did the following:
$ sudo apt-get install libmysql-ruby
$ sudo gem install mysql
  • When you create your Rails application, you need to specify MySQL. Until I get a better name, I'm calling my game "smig" (stock market investment game).
$ rails --database=mysql smig
$ cd smig
  • You need to initialize the database.
$ rake db:create RAILS_ENV='development'
$ rake db:migrate
  • Your brand new (empty) application is now ready to run. You can actually run it! But, you need a webserver. Fortunately, Rails includes the simple WEBrick webserver for development purposes. You can run it with:
$ script/server
  • Now you can see your new web application by browsing to: http://localhost:3000
All you will see is the "You're running with Rails" welcome screen (shown below), but at least that lets you know you've got something running.
Next step: Getting smig to actually do something . . .