570 likes | 814 Views
Developing Web Application using Ruby on Rails. Ben Curren CTO and Founder. Agenda. What is Ruby on Rails? Overview of Rails Create a Todo List Web Application using Rails Introduction to Ruby More Information Questions. My Background. Started developing Java in 1996
E N D
Developing Web Application using Ruby on Rails Ben CurrenCTO and Founder
Agenda • What is Ruby on Rails? • Overview of Rails • Create a Todo List Web Application using Rails • Introduction to Ruby • More Information • Questions
My Background • Started developing Java in 1996 • Developed many web based applications using Java / J2EE, PHP and ASP.net. • Have worked extensively with C++ / C developing Windows desktop applications. • Developed desktop application using WinForms and .Net 1.1. • Have been working with Ruby on Rails for about months. • CTO and Founder of Esomnie. We develop web applications using Ruby on Rails, Java, and ASP.net.
Assumptions about the audience • I have made a couple assumptions about the audience: • You have experience with an object-oriented programming language. • You understand the basics of HTTP. • You understand XHTML / HTML
What is Ruby on Rails? • Rails is a web development framework • Ruby is a programming language • Rails is developed in Ruby.
What is Rails? • Full stack web application framework • Open source and Free • Active and growing community
What does Rails Provide? • MVC • ActiveRecord • Unit Testing Framework • Migrations • And ActiveResource, ActionWebService, ActiveSupport, ActionMailer, ActionPack
Rails Opinions • Convention over configuration • Agile software development • Test driven development
The application • A web application that allows a user to create a todo list • Users will be able to view a list of their todo lists. • Users will be able to create new todo lists. • They will be able to add items to the list. (not today, we will not have time)
Create the project • Create a new rails project named todo. • Creates the rails directory structure and initial configuration. rails todo
Directory Structure todo app controllers helpers models views layouts config db public script test functional unit integration vendor …
Create the databases • Create a file called db/create.sql • Run the script with mysql -uroot -p < db/create.sql create database todo_development; create database todo_test; create database todo_production; grant all on todo_development.* to 'tododev'@'localhost' identified by 'tododev'; grant all on todo_test.* to 'todotest'@'localhost' identified by 'todotest'; grant all on todo_production.* to 'todo'@'localhost' identified by 'todo';
Update the Database Configuration • Supply the username and password in config/database.yml development: adapter: mysql database: todo_development username: tododev password: tododev host: localhost test: adapter: mysql database: todo_test username: todotest password: todotest host: localhost production: adapter: mysql database: todo_production username: todo password: todo host: localhost
Generate the List model • Create the List model. • It will hold the name of the todo list. script/generate model list exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/list.rb create test/unit/list_test.rb create test/fixtures/lists.yml create db/migrate create db/migrate/001_create_lists.rb
Create the List Migration • A migration allows you to modify the database schema using Ruby. • Migrations provide versioning. • Update the file called db/migrate/001_create_lists.rb class CreateLists < ActiveRecord::Migration def self.up create_table :lists do |t| t.column "name", :string t.column "created_at", :string t.column "updated_at", :string end end def self.down drop_table :lists end end
Run the Migrations rake migrate (in /Users/bcurren/projects/todo) == CreateLists: migrating ================================ -- create_table(:lists) -> 0.4252s == CreateLists: migrated (0.4269s) =======================
The List Model • Without writing any mapping code, you can start using the List model. • Here are the contents of app/model/list.rb class List < ActiveRecord::Base end
Create and Store a List Object script/console Loading development environment. >> list = List.new => #<List:0x256680c @attributes={"name"=>nil, "updated_at"=>nil, "created_at"=>nil}, @new_record=true> >> list.name = "Ben's Todo List" => "Ben's Todo List" >> list.save => true
Require List.name • Make the name of the list required. • Update the contents of app/model/list.rb class List < ActiveRecord::Base validates_presence_of :name end
Test that List.name is required • Add a test to make sure name is required. (test/unit/list_test.rb) class ListTest < Test::Unit::TestCase fixtures :lists def test_name_required List.new do |list| list.name assert !list.valid? assert list.errors.on(:name) end end end
Run the Unit Tests rake test:unit (in /Users/bcurren/projects/todo) /usr/local/bin/ruby -Ilib:test "/usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/unit/list_test.rb" Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader Started Finished in 0.103404 seconds. 1 tests, 2 assertions, 0 failures, 0 errors
Create the list of todo lists • Create a list controller with an action named list • The action list uses the model to get all the todo lists and places them in a variable called @lists • Create a view the loops over the @lists and renders the html view
Create the ListController script/generate controller List list exists app/controllers/ exists app/helpers/ create app/views/list exists test/functional/ create app/controllers/list_controller.rb create test/functional/list_controller_test.rb create app/helpers/list_helper.rb create app/views/list/list.rhtml
The ListController • The generated file app/controllers/list_controller.rb class ListController < ApplicationController def list end end
The list action • Need to create an array of List objects in the database. • app/controllers/list_controller.rb class ListController < ApplicationController def list @lists = List.find :all end end
The ListControllerTest • The generated list controller test in test/functionals/list_controller_test.rb class ListControllerTest < Test::Unit::TestCase def setup @controller = ListController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end end
The test for the list action • I added the test for the list action in The generated list controller test in test/functionals/list_controller_test.rb. def test_list get :list assert_response :success assert_template 'list' assert_not_nil assigns(:lists) end
Run the functional tests rake test:functionals (in /Users/bcurren/projects/todo) /usr/local/bin/ruby -Ilib:test"/usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/functional/list_controller_test.rb" Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader Started Finished in 0.095025 seconds. 1 tests, 3 assertions, 0 failures, 0 errors
The list view • Update the template app/views/list/list.rhtml to display a list of the todo lists. <h1>Todo Lists</h1> <ul id="todo_list"> <%= render :partial => 'list', :collection => @lists %> </ul>
The list partial • Create a file name app/views/list/_list.rhtml to display each list item. <li><%= list.name %></li>
Check your work • Start up the web server. WEBrick comes with Rails and is great for testing. script/server & [1] 6686 harley:~/projects/todo bcurren$ => Booting WEBrick... => Rails application started on http://0.0.0.0:3000 => Ctrl-C to shutdown server; call with --help for options [2006-10-08 09:50:46] INFO WEBrick 1.3.1 [2006-10-08 09:50:46] INFO ruby 1.8.4 (2005-12-24) [powerpc-darwin8.6.0] [2006-10-08 09:50:46] INFO WEBrick::HTTPServer#start: pid=6686 port=3000
View the list in the browser • Open your browser and type in the URL http://localhost:3000/list/list
Add a default layout to your pages • Create a layout named app/views/layouts/default.rhtml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <%= javascript_include_tag :defaults %> </head> <body> <%= @content_for_layout %> </body> </html>
Add the layout to the ApplicationController • Open the file app/controllers/application_controller.rb • All of the controllers in the app will now use the layout default. You can override this in each controller. class ApplicationController < ActionController::Base layout 'default' end
Create a new todo list using AJAX • First, let’s create the form on the app/views/list.rtml page. <div> <%= form_remote_tag( :url => {:controller => 'list', :action => 'add'}, :html => {:id => 'add_item_form',}) %> <label for="list_name">Name:</label> <%= text_field 'list', 'name', :size => 20 %> <%= submit_tag 'Create' %> <%= end_form_tag %> </div>
Create the add action • Add the following action to app/controllers/list_controller.rb def add @list = List.new(params[:list]) @list.save! end
Create the add rjs file • Create a file named app/views/list/add.rjs page.insert_html :bottom, "todo_list", :partial => 'list' page.visual_effect :highlight, "todo_list" page.form.reset 'add_item_form'
Test the AJAX add • The functional test requires a plugin and I don’t have time to include it here. See http://glu.ttono.us/articles/2006/05/29/guide-test-driven-rjs-with-arts for a good example. • http://localhost:3000/list/list
The application stats rake stats (in /Users/bcurren/projects/todo) +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Helpers | 5 | 4 | 0 | 0 | 0 | 0 | | Controllers | 16 | 12 | 2 | 2 | 1 | 4 | | Components | 0 | 0 | 0 | 0 | 0 | 0 | | Functional tests | 20 | 16 | 2 | 3 | 1 | 3 | | Models | 3 | 3 | 1 | 0 | 0 | 0 | | Unit tests | 13 | 11 | 1 | 1 | 1 | 9 | | Libraries | 0 | 0 | 0 | 0 | 0 | 0 | | Integration tests | 0 | 0 | 0 | 0 | 0 | 0 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 57 | 46 | 6 | 6 | 1 | 5 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 19 Test LOC: 27 Code to Test Ratio: 1:1.4
What is Ruby • Object-oriented, dynamic scripting language • Developed by Yukihiro Matsumoto in 1995 • Flexible and simple syntax • Based on Perl, Smalltalk, Eiffel, Ada and Lisp
Ruby is Object-Oriented • default_expiration_date is a public static method of CreditCard • day is a method of FixNum • day returns the number of seconds in x days • from_now is a method of FixNum • from_now returns the x seconds from now class CreditCard def self.default_expiration_date 1.day.from_now end end
Ruby is Dynamic • Ruby has open classes. • You can open up a class and add or override methods. • The methods day and from_now are not part of the Ruby FixNum class. Rails adds them with the ActionPack module. class FixNum def days self * 24.hours end alias :day :days end
Ruby is Really Dynamic • Add methods, instance, methods and more at runtime. • This can create an accessor and instance variable like this. class CreditCard attr_writer :number end
Adding methods and variables at runtime • attr_writer could be implemented like this. class Object def self.attr_writer(method) eval %Q{ def #{method.to_s}=(value) @#{method.to_s} = value end } end end
The Magic of method_missing • How would you write a method that prints out its name if the method name starts with print_? • For example: Example.print_my_name prints “print_my_name” class Example def self.method_missing(method_name, *args) puts method_name if method_name =~ /^print_/ end end
Ruby’s Closures (Blocks) • A closure allows a programmer to provide a block of code for a method to run. • This example prints out each search engine. (taken from www.ruby-lang.org) search_engines = %w[Google Yahoo MSN].map do |engine| “http://www.” + engine.downcase + “.com” end