SlideShare a Scribd company logo
1 of 39
Download to read offline
The Rails Cookbook
A Ruby on Rails Crash Course
         Brian Hogan
The Rails Cookbook

The Rails Cookbook: A Ruby on Rails Crash Course
Brian Hogan

Published 2008
Copyright © 2009 Brian P. Hogan




Copyright 2009 Brian P. Hogan                      2
The Rails Cookbook




Copyright 2009 Brian P. Hogan   3
Dedication


Dedication
     This book is dedicated to the Web Development students at the University of Wisconsin-Eau Claire, past, present, and
     future.




Copyright 2009 Brian P. Hogan                                                                                               i
The Rails Cookbook


Table of Contents
     1. Introduction ............................................................................................................................................. 1
            1. Rails ............................................................................................................................................... 1
            2. Basic Concepts ................................................................................................................................. 1
                  2.1. MVC Design Pattern ............................................................................................................... 1
                  2.2. Agile Programming Techniques ................................................................................................ 2
                  2.3. Other features and components of Rails ..................................................................................... 2
            3. Installing Ruby on Rails .................................................................................................................... 3
     2. Your First Rails Project - A Cookbook ......................................................................................................... 4
            1. Configuring your Database ................................................................................................................. 4
                  1.1. Configuring the Database ......................................................................................................... 5
            2. Creating the Recipes interface using Scaffolding .................................................................................... 6
                  2.1. Migrations ............................................................................................................................. 7
                  2.2. The migration file .................................................................................................................. 7
                  2.3. Creating the table from the migration ......................................................................................... 8
            3. Test it out ....................................................................................................................................... 8
            4. How did we get all that? .................................................................................................................... 8
     3. Validating User Input ................................................................................................................................ 9
            1. Validations ...................................................................................................................................... 9
            2. Unit Tests ...................................................................................................................................... 10
                  2.1. How Tests Work .................................................................................................................. 11
                  2.2. Fixtures ............................................................................................................................... 11
                  2.3. Running the Test .................................................................................................................. 12
            3. Providing Feedback to Users ............................................................................................................. 12
     4. Cleaning Up the Scaffolding ..................................................................................................................... 14
            1. Cleaning up the List page ................................................................................................................. 14
                  1.1. Helpers ............................................................................................................................... 15
            2. Cleaning up the Show page .............................................................................................................. 16
            3. Using Partials to share common code ................................................................................................. 17
            4. Where’s the rest of my HTML? ......................................................................................................... 17
     5. Adding Categories ................................................................................................................................... 19
            1. Create a category model and table ..................................................................................................... 19
            2. Adding some default records with Rake .............................................................................................. 19
            3. Modifying the Recipes table ............................................................................................................. 19
            4. Creating an Association Between a Recipe and a Category ..................................................................... 20
                  4.1. Lazy vs. Eager Loading ......................................................................................................... 20
            5. Adding categories to the controllers and views ..................................................................................... 21
                  5.1. The New and Edit forms ........................................................................................................ 21
                  5.2. The Show view .................................................................................................................... 22
                  5.3. The List view ...................................................................................................................... 22
            6. Test it out ...................................................................................................................................... 22
     6. Other Rails Tidbits .................................................................................................................................. 23
            1. Writing Documentation with RDoc .................................................................................................... 23
            2. Annotating Models .......................................................................................................................... 24
            3. Debugging and Exploring with Console .............................................................................................. 24
            4. Logging ......................................................................................................................................... 25
            5. Writing your own SQL statements ..................................................................................................... 25
     7. Development and Deployment ................................................................................................................... 27
            1. Exploring Development Tools ........................................................................................................... 27
            2. Deploying Rails Applications ............................................................................................................ 27
     8. Homework and Exploration ...................................................................................................................... 29
     9. Where To Go Next? ................................................................................................................................ 30
            1. Books ........................................................................................................................................... 30
            2. Online Resources ............................................................................................................................ 30




Copyright 2009 Brian P. Hogan                                                                                                                                       ii
The Rails Cookbook

     Index ........................................................................................................................................................ 32




Copyright 2009 Brian P. Hogan                                                                                                                                      iii
The Rails Cookbook


List of Figures
     3.1.   User Feedback as provided by Rails validations .........................................................................................             13
     4.1.   The modified Index page .......................................................................................................................      15
     4.2.   The Show Page ....................................................................................................................................   16
     6.1.   RDoc output in HTML ..........................................................................................................................       23
     6.2.   Annotations added to a model .................................................................................................................       24
     6.3.   Using the Rails Console to work with objects ............................................................................................            25




Copyright 2009 Brian P. Hogan                                                                                                                                    iv
Introduction


Chapter 1. Introduction
     Get ready to forget everything you know about web developent, because Ruby on Rails will change your world. Web
     development with Ruby on Rails is one of the fastest ways to build quality applications in a fraction of the time, and all
     it takes is a little patience and a little time. If you've ever wanted to get started with this technology, this guide is for you.

     This simple yet detailed tutorial will guide you through the steps to build a working cookbook application using the
     Ruby on Rails framework. This guide is meant to expose you to the Rails framework and is not meant to explain all of
     the concepts in depth. When you’re finished with this tutorial, you will have a better understanding of the basic concepts
     behind Rails and you should have a basic understanding of how basic Rails applications are structured.


  1. Rails
     Ruby on Rails is an amazing framework designed to make building high-quality, tested, stable, and scalable database-
     driven web applications easy. The Rails framework provides developers with the tools to create web applications using
     Agile programming methodologies such as rapid prototyping, test-driven development, and easy refactoring.

     Ruby is a dynamically-typed fully object-oriented scripting language used primarily in Japan until it drew the attention of
     a developer from 37Signals. The developer, David Heinemeier Hansson, was working on a new project called Basecamp.
     David felt very limited by the languages he was using to develop the project and so he started working with Ruby, taking
     advantage of all of the built-in features of the language.

     In July 2004, David released the Rails framework which he extracted from his work on Basecamp. Several versions later,
     Rails has burst onto the scene and attracted the attention of many development shops and industry leaders including
     Amazon, Oracle, Boeing, Thoughtworks, and many others.


  2. Basic Concepts
     Let's take a bit and look at the basic concepts of the Rails framework.


     2.1. MVC Design Pattern
        The MVC or Model-View-Controller pattern explicitly splits up your code and separates business logic from pre-
        sentation and flow control logic. It also provides mechanisms for easy reuse of code. Traditional web applications
        written in ASP, PHP, or ColdFusion tend to have scripts intermingled with business logic. Developers can avoid this
        but without a design pattern such as MVC, the process tends to be trial and error.


        The components of MVC

           Models contain all business rules and data interaction. All database-related CRUD (Create, Read, Update, and
           Delete) code belongs in the model as well. If this pattern is followed correctly, you’ll never write a select statement
           anywhere outside of the model. Instead, you will access your data by calling a method on the model.

           Views are what your end users will see. They are the web pages in a web application, or the user screens in a
           desktop application. They should contain very little presentation logic and should be optimized for reuse. Views
           should never interact directly with models.

           Controllers are the glue of the application. Controllers receive user requests, retrieve data from the models, and
           then send the appropriate view to the user.



Copyright 2009 Brian P. Hogan                                                                                                             1
Introduction


        Rails-specific MVC components
           The Rails framework divides the View layer into three separate pieces.

           Layouts contain your overall template and can be mapped to a controller or a specific view. Instead of placing and
           repeating your entire layout HTML in each view page, you centralize it in the layout. There’s no need to split a
           layout into various pieces like a header and footer either. This makes layouts easy to design.

           Helpers provide a mechanism to store presentation-related code. Helpers are very similar to a “code-behind” page.
           Rails comes with hundreds of pre-written helpers built in, but Rails makes it easy to define your own. This way
           you can avoid lots of messy logic code in your view pages.

           Partials are pieces of views that need to be used over and over. The web form that lets a user create a new entry
           might contain the same fields as the form that the user will use to update or edit that entry. Partials are used to
           centralize that code for easy reuse.


     2.2. Agile Programming Techniques

        Test-driven development
           Test-driven development (TDD) is a programming methodology where you write tests to prove that your code
           actually works. In an ideal world, you will write your tests first and then write enough application code to make
           your tests pass.

           For example, a developer will create a unit test to create a new user. The test will fail until the developer actually
           writes the code that creates the user. The developer writes the code and continues to run the tests until they pass..
           If they don’t pass, the developer knows that his or her functional code is wrong. If you write your tests first, the
           tests are always guaranteed to be current. New tests are added when new features are added, and tests are changed
           to reflect new requirements.

        Refactoring
           According to Martin Fowler, a senior consultant at Thoughtworks, the basic idea is that you make small changes to
           your code to improve your design, making it easier to understand and to modify. Refactoring enables you to evolve
           your code slowly over time, to take an iterative and incremental approach to programming. Martin's refactoring
           site, www.refactoring.com, is a good online resource.

           Rails makes refactoring easy. Because of the strict adherence to the MVC pattern, it’s trivial for experienced
           developers to take an entire section of an application and rewrite it without breaking the entire application.


     2.3. Other features and components of Rails
        Generator scripts help you create Rails models, views, and controllers.

        Mongrel is a Ruby-based web server which is used in development and deployment so you can test your application
        without having to jump through deployment hoops.

        Runner is a script that allows you to execute your application code from outside of the Rails application. This is
        useful if you want to use a task scheduling program to periodically invoke some application code.

        Unit tests contain the code that you use to test your models.

        Functional tests contain code you use to test your controllers and views



Copyright 2009 Brian P. Hogan                                                                                                       2
Introduction

        Migrations allow you to define a database-agnostic schema incrementally, with the ability to roll back your changes.
        You can use Migrations to easily develop on SQLite, stage to MySQL, and deploy on Oracle.

        Plugins allow developers to add new features to the framework at almost any level. Plugins can be used to introduce
        new features, override existing ones, modify the Ruby core classes, or even share common models and controllers
        across multiple applications. Plugins are easy to write and seamless to use. They allow the Rails core team to deny
        many feature requests, keeping the Rails framework small and agile

        Rake is a Ruby program that runs user-defined tasks. Rails includes many tasks that help you manage your application.

        Finally, Rails provides the ability to “freeze” your application to the current version of Rails that you used for devel-
        opment. A simple Rake task bundles Rails with your application, ensuring that your application remains safe when
        the Rails framework is updated.


    3. Installing Ruby on Rails
     Download the One Click Ruby Installer1 for Windows and run the installer, accepting all of the defaults.

     Next, open a command prompt and type

     gem update --system

     gem install rails

     gem install mongrel

     This will get your environment set up using the current stable release of Rails. The Gem package management tool helps
     you install Ruby libraries that you want to use system-wide. You have to have administrative privileges though, so if
     you don’t, you’ll need to have an administrator run those commands for you.

        Working with Older Versions of Rails

        This document is written with Rails 2.3.2 in mind. It is possible that the version of Rails that's currently provided
        by Rubygems is newer. This may cause some problems as things change rapidly with Rails and things are dep-
        recated or moved into plugins. However, it's easy to have multiple versions of the Rails framework installed on
        your machine, thanks to Rubygems.

        The command gem list rails will quickly tell you which versions of Rails you have installed. To install
        a specific version of Rails, you simply issue this command:

        gem install rails -v=2.3.2

        To install Rails 1.2.3 in order to follow along with some older books and tutorials, install it with

        gem install rails -v=1.2.3




1
 http://rubyforge.org/frs/download.php/47082/ruby186-27_rc2.exe




Copyright 2009 Brian P. Hogan                                                                                                       3
Your First Rails Project - A Cookbook


Chapter 2. Your First Rails Project - A
Cookbook
     We're going to build a simple cookbook that will let us keep track of our favorite recipes. Each recipe will have ingre-
     dients, instructions, and a title. Eventually you'll be able to associate a category to the recipe.

     Create a new Rails project by opening a command window and typing

     rails cookbook


        Generating a project using a specific Rails version

        If you have multiple versions of Rails installed via RubyGems, you can choose which version of Rails you wish
        to use for your application. For example, if you need to use Rails 2.3.2 to follow along with this book, you can
        install Rails 2.3.2 with

        gem install rails -v=2.3.2

        and then create the cookbook project with

        rails _2.3.2_ cookbook

        The _2.3.2_ parameter tells RubyGems which version to use. To use Rails 1.2.3 to follow along with the famous
        Depot application in Agile Web Development with Rails - Second Edition, you simply create the project with

        rails _1.2.3_ depot

        That's all there is to it.

     This command will create the folder cookbook and place a whole bunch of framework files in that folder. As you move
     through this tutorial, you’ll notice that Rails has many generators that build files for you. Generators are great for file
     creation and laying down code that’s generic.


  1. Configuring your Database
     Open the file config/database.yml and review the contents of the file. It should look something like this:

       1    # SQLite version 3.x
       2          #   gem install sqlite3-ruby (not necessary on OS X Leopard)
       3          development:
       4            adapter: sqlite3
       5            database: db/development.sqlite3
       6            pool: 5
       7            timeout: 5000
       8
       9             # Warning: The database defined as "test" will be erased and
      10             # re-generated from your development database when you run "rake".
      11             # Do not set this db to the same as development or production.
      12             test:
      13               adapter: sqlite3
      14               database: db/test.sqlite3
      15               pool: 5
      16               timeout: 5000
      17
      18             production:




Copyright 2009 Brian P. Hogan                                                                                                      4
Your First Rails Project - A Cookbook

      19              adapter: sqlite3
      20              database: db/production.sqlite3
      21              pool: 5
      22              timeout: 5000
      23


     This is a YAML file. (rhymes with camel) It’s a structured configuration format that maps directly to nested hashes
     in Ruby and is very common for configurations in Ruby on Rails. Tabs must not be used in YAML files. Instead, two
     spaces are used for each indentation.

                  Set Your Spaces

                  Now would be a good time to ensure that the text editor you're using has soft-tabs instead of regular tabs.
                  To ensure that your Ruby code fits in with that of other developers, you want to set your tabs to 2 spaces.

     • Adapter is the database adapter that we want to use. Examples are mysql, sql_server, oracle, postgresql, sqlite3, and
       sqlite. We’re using sqlite3 because it’s easy for beginners, requires no setup, and is the default database for a new
       Rails project.

     • Database is the name of the database. In this case, it’s the path to the database file. Other complex adapters would
       have you specify the database name or Oracle TNSNames entry here, and then you would have host, username, and
       password fields as well.


     1.1. Configuring the Database
        With SQLite3, the database does not need to exist before we start the project; it will be created for you when you
        run your first migration (but don’t worry about that just yet!) Other databases like MySQL or Microsoft SQL Server
        require that the database (or schema) exist and that the appropriate privileges are applied. Since we’re trying to get
        you excited about Rails, we want to keep the momentum going. Using SQLite as a database makes it really simple
        to create a working rapid prototype. You can then move to a different database later, because you’ll define your
        database tables using pure Ruby code instead of database-specific SQL DDL statements.

        Installing SQLite3 on Windows
           1. Download the files sqlite3.exe and sqlite3.dll and place them in your c:rubybin folder so that they are
              available on your path.

              Get sqlite3.exe from http://www.sqlite.org/sqlite-3_6_13.zip

              Get sqlite3.dll from http://www.sqlite.org/sqlitedll-3_6_13.zip

              Extract these files to c:rubybin

           2. Open a command prompt and type

              gem install sqlite3-ruby

                           SQLite3 is Broken on Windows

                           To install SQLite3-ruby on Windows, simply specify version 1.2.3.

                           gem install sqlite3-ruby -v=1.2.3

                           This will install a version that will work perfectly for Windows.




Copyright 2009 Brian P. Hogan                                                                                                    5
Your First Rails Project - A Cookbook

              When it finishes installing, you’re good to go!



  2. Creating the Recipes interface using Scaffold-
  ing
     Since we’re writing a cookbook, the logical place to start would be with recipes.

     Rails uses generators to help you do some common tasks. We’ll use a generator to create a scaffold.

     Scaffolding is the much talked about but poorly understood feature of Rails. It’s meant to be a starting point… to give
     you a quick interface where you can do some simple testing and get some of the mundane repetitive code written for
     you. However, scaffolding can only take you so far and is not meant for use in production, hence the name “scaffolding”.
     There are some steps you’ll need to take to clean up the scaffolding.

     Let’s create a simple interface that will allow us to manage recipes in the system. The scaffold generator creates a model,
     controller, a set of views, and a migration, or a table definition. At the command prompt, move into your cookbook
     project folder

     cd cookbook

     The generate scaffold command takes several parameters. The first parameter is the model name. Model names are
     singular. The generator will use this model name to create a controller and a definition for a database table. Both of
     these, by convention, will be pluralized. The second parameter is a string that defines your database table structure.
     Each field can be specified along with its data type. The scaffold generator uses this information to build the web forms
     your users will see. They won’t be pretty but they will work.

     Type (all on one line)

     ruby    script/generate                 scaffold           recipe        title:string             ingredients:text
     instructions:text

     The generator runs, creating the following output:

          exists  app/models/
                exists app/controllers/
                exists app/helpers/
                create app/views/recipes
                exists app/views/layouts/
                exists test/functional/
                exists test/unit/
                create test/unit/helpers/
                exists public/stylesheets/
                create app/views/recipes/index.html.erb
                create app/views/recipes/show.html.erb
                create app/views/recipes/new.html.erb
                create app/views/recipes/edit.html.erb
                create app/views/layouts/recipes.html.erb
                create public/stylesheets/scaffold.css
                create app/controllers/recipes_controller.rb
                create test/functional/recipes_controller_test.rb
                create app/helpers/recipes_helper.rb
                create test/unit/helpers/recipes_helper_test.rb
                 route map.resources :recipes
            dependency model
                exists    app/models/
                exists    test/unit/
                exists    test/fixtures/
                create    app/models/recipe.rb
                create    test/unit/recipe_test.rb




Copyright 2009 Brian P. Hogan                                                                                                      6
Your First Rails Project - A Cookbook

                 create       test/fixtures/recipes.yml
                 create       db/migrate
                 create       db/migrate/20090419054911_create_recipes.rb


     The generator created a recipe model, and it also created a controller called recipes_controller.rb. The con-
     troller will contain all of the logic that handles user requests and interacts with the models. In fact, if we look in there,
     it’s already written it for us! It’s got code to handle creating, editing, listing, viewing, and deleting of recipes. Because
     these are all common tasks, the generators can do a pretty solid job of handling this for us.

     One major problem with scaffolding is that it’s not dynamic. Now that we’ve generated these, we can’t rely on scaffold-
     ing any more. Any manual changes we make would be destroyed if we attempted to run the scaffold generator again.
     That means that if we change the table, we’ll need to modify the views. That’s okay though because we already have
     a good starting point.

     The model we just created requires a database table called “recipes”. Normally, you’d go and create that database table
     using some sort of SQL statement or visual tool. In Rails, we use migrations.


     2.1. Migrations
        Migrations are used to modify your database. You use them to execute DDL statements against your database system.
        One of the best things about them is that they allow you to define your database as it changes; you can roll your
        changes back if they don’t work without worrying about goofing up your database.

        They’re also an invaluable tool when moving to production. Migrations are supported by all of the Rails database
        adapters. This means that you can change database systems and apply the migration to the new database which will
        create your structures for you. This eliminates the need to know the various dialects of data definition languages that
        may change across database systems. Developers can test with SQLite3, develop with MySQL, and deploy to Oracle.


     2.2. The migration file
        Open the file dbmigrateXXXXXXXX_create_recipes.rb. The XXXXXXX part will be a numerical
        timestamp for the moment in time the file was created. This timestamp will help the Rails Migration system deter-
        mine if it's been applied, and it also allows multiple developers to modify an application's schema without creating
        bottlenecks. It’s contents should resemble this:

          1    class CreateRecipes < ActiveRecord::Migration
          2      def self.up
          3        create_table :recipes do |t|
          4         t.string :title
          5         t.text :ingredients, :instructions
          6         t.timestamps
          7        end
          8      end
          9
         10      def self.down
         11        drop_table :recipes
         12      end
         13    end


        Rails uses the information in this file to create a ‘recipes’ table in the database. Note that the above definition does
        not include a primary key field. Unless you specify otherwise, Rails will create an ‘id’ column automatically, and
        will mark it as a primary key.

        Why is the table name “recipes” and not “recipe”? Remember that by default, Rails likes table names to be the plural
        form of your model. It’s pretty smart too because it can do things like person => people and category => categoies.
        This isn’t mandatory but if we follow these conventions, we can save a few lines of code and skip a few steps. Rails
        will automatically look for the recipes table when we access the Recipe model in our code.



Copyright 2009 Brian P. Hogan                                                                                                        7
Your First Rails Project - A Cookbook


     2.3. Creating the table from the migration
        At this point, the table doesn’t actually exist in our database—we just have the “blueprint” for it in Ruby code. To
        execute the migration, we’ll run the command

        rake db:migrate

        from our command line. Run that command and you’ll see feedback stating that our recipes table was created.

        (in C:/rails/workspace/cookbook)
        == 1 CreateRecipes: migrating ================================================
        -- create_table(:recipes)
           -> 0.0310s
        == 1 CreateRecipes: migrated (0.0310s) =======================================




  3. Test it out
     Would you believe that’s all you have to do to get a simple application written with Rails? Start the internal server and
     test out your application. At the command prompt, enter

     ruby script/server

     and wait a few seconds until you see that the server has in fact started.

     Navigate to http://localhost:3000/recipes/ and you should be able to enter a few recipes into the system. Once you’ve
     entered a few recipes, continue with the tutorial. The application works, but it’s a long way from good.


  4. How did we get all that?
     When you generated the Recipe model, it created a new class that extends a class called ActiveRecord::Base. This parent
     class contains all of the functionality needed to create, read, update, and delete records from a database. This parent
     class makes all kinds of dynamic assumptions about your database connection. As we discovered before, it uses the
     class name (recipe) and pluralizes it to figure out what database table to use, and It uses your database.yml to find
     out what database server to use.

     The first time you access a model in a Rails application, the application connects to the associated database server and
     queries the database for the information about the table. It uses this information to dynamically build methods for data
     storage and retrieval.

     The Scaffold generator you ran uses that technique to build an interface that will let you create, read, update, delete, and
     list the rows of the recipes table. It uses the information your model has obtained and then builds HTML forms for data
     entry, using the data types specified by your database table’s configuration.

     So instead of having to write code to connect to a database and then build data entry forms, you can use the scaffolding
     feature of Rails as a starting point. This is just the beginning though. There's a lot more to Rails than just scaffolding an
     application from a single table.. In fact, most professional Rails developers don’t use scaffolding at all.




Copyright 2009 Brian P. Hogan                                                                                                        8
Validating User Input


Chapter 3. Validating User Input
     You may notice that if you entered recipes into the system without filling in any fields, the data was still placed into the
     database. You will definitely want to require that people enter certain fields into the database.

     We’re going to do this with some simple validations and a simple unit test to ensure that our validations work.

     In Rails, validation is done in the model. This is actually good practice because the models could be used outside of the
     Web. The MVC pattern standard is to place all business logic and business rules in the models and have only presentation
     logic in the views and controllers.


        A word about models

        Our model class has very little code. In fact, it really has no code at all. As you learned earlier, its parent class
        does all of the work.

        Normally, Ruby classes use methods for accessing instance variables in a class. ActiveRecord, the ORM library
        used by Rails, attempts to build methods dynamically based on the metadata in your database. The class is mapped
        to a table and upon first use, ActiveRecord creates an instance of the class and builds the accessor methods (and
        many many other methods). In production mod, this reflection is only done once until the application is restarted
        by a server admin.

        Each field in our table becomes an accessor (a Ruby term meaning that it can be read and written to). For example,
        we said a recipe has a title. Our Recipe class will have a method called title which can be used as a getter
        and a setter.



  1. Validations
     Validations are special methods provided by the Validations feature in Active Record. There are quite a few built-in
     methods we can use to validate data. For simplicity, we’ll use only validates_presence_of on our Recipe model.

     Open app/models/recipe.rb and change the contents to

        1 class Recipe < ActiveRecord::Base
        2   validates_presence_of :title, :ingredients, :instructions
        3 end
        4


     Notice that we use symbols as the parameters to the validates_presence_of method. Symbols are a special type of string
     used in Ruby to denote a value. For now, just think of them as immutable strings. Ruby developers often use them as
     keys in hashes.

     One of the interesting things about Ruby is that methods can be defined so they take any number of parameters. In this
     case, the validates_presence_of method is taking in an array of symbols which represent the database fields
     that need to be validated.

     This simple line of code is all we need to make sure that users enter something for the title, ingredients, and instructions
     for a recipe. It’s not foolproof, but it’s a good start.

     If you want to see what other types of validations are out there, take a look at this page in the Rails API: http://
     api.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html



Copyright 2009 Brian P. Hogan                                                                                                       9
Validating User Input


  2. Unit Tests
     We need to put on the brakes here and write a quick unit test to ensure that our validation works. Unit tests are built
     right into the Rails framework and are designed to test the functionality of your individual models. Unit tests become
     vitally important to your development process because they allow you to test your business logic and prove that things
     are working at the model level. This way you don’t have to keep using a browser to track down bugs that aren’t related
     to the display.

                  Write Tests First!

                  Normally, we'd have written our test cases before we implemented any code. This is one reason why
                  scaffolding is bad; it discourages you from doing the right thing. However, since you're new to Rails, we're
                  doing things a little bit differently.


     Rails automatically generated a unit test skeleton for recipe when we generated the recipe model. Open the file test/
     unit/recipe_test.rb and change the contents to the following:

       1 require 'test_helper'
       2
       3 class RecipeTest < ActiveSupport::TestCase
       4
       5   def test_should_create_valid_record
       6     recipe = Recipe.new
       7     recipe.title = "Ice water"
       8     recipe.ingredients = ["one glass","water","ice"].join("<br>")
       9     recipe.instructions = "Combine all ingredients into the glass and let sit for two minutes.
      Serve immediately."
      10     assert_kind_of Recipe, recipe
      11     assert recipe.save
      12   end
      13
      14   def test_should_not_save_unless_title_exists
      15     recipe = Recipe.new
      16     assert !recipe.save # save should fail because there are errors.
      17     assert_equal "can't be blank", recipe.errors.on(:title)
      18   end
      19
      20   def test_should_not_save_unless_ingredients_exists
      21     recipe = Recipe.new
      22     assert !recipe.save # save should fail because there are errors.
      23     assert_equal "can't be blank", recipe.errors.on(:ingredients)
      24   end
      25
      26   def test_should_not_save_unless_instructions_exists
      27     recipe = Recipe.new
      28     assert !recipe.save # save should fail because there are errors.
      29     assert_equal "can't be blank", recipe.errors.on(:instructions)
      30   end
      31
      32 end
      33


     That might look complicated, but let's break it down. We have four methods there…

     test_should_create_valid_record,

     test_should_not_save_unless_title_exists,

     test_should_not_save_unless_ingredients_exists, and



Copyright 2009 Brian P. Hogan                                                                                                    10
Validating User Input

     test_should_not_save_unless_instructions_exists.

     test_should_create_valid_record simply creates a new instance of Recipe, sets the values for the recipe,
     and then saves the record. Save should return true, so we use assert to evaluate the value of save. If it evaluates to true,
     this test passes. If not, it fails. This one needs to pass all the time, as it’s the baseline test. If this test starts failing, that’s
     an indication that the program’s logic has changed.

     The other three tests simply attempt to save the record without setting one of the required fields. We expect these to fail
     because of our validations—in this test we haven’t actually provided any of the required fields, but we are testing for
     only one error at a time to avoid making our tests too complicated.. We’re also asserting the inverse of true for the save.
     (assert that Recipe.save is not true. Then we assert that the error messages are set for each field. Each validation has its
     own message format. In this case, the validates_presence_of validation stores “can’t be blank” in the errors collection,
     under a key for each invalid attribute. If the title isn’t blank, you’ll find the error message for that in the errors collection,
     under the :title key. How Tests Work


     2.1. How Tests Work
        Tests actually work by using the test database you defined in database.yml earlier. A test file starts by dumping
        everything in your database and then updating it so it’s consistent with your development database. Never use the
        same database for production, development, and tetsting!!!!

        Each test file is independent of the others. You can feel free to delete as many records as you want in a test and they
        will be recreated when you start the test again.

        Each method that starts with ‘test_’ will be run as part of the test suite.


     2.2. Fixtures
        Tests can get data from fixtures. Fixtures are loaded into each test by the fixtures method. You’ll need a fixture for
        each table in your database, not each model in your system.

        Modify the fixture for the recipes table by editing /test/fixtures/recipes.yml and add a few recipes.

                        Note

                        Be careful not to use tabs and also be sure to leave a space after each colon! YAML is a tricky little
                        format.


          1 ice_water:
          2           title: "Ice Cream"
          3           ingredients: "3 scoops vanilla ice cream<br>chocolate syrup"
          4           instructions: "Scoop ice cream into the bowl and pour chocolate syrup on top."
          5         toast:
          6           title: "Toast"
          7           ingredients: "bread, butter, jelly"
          8           instructions: "Place bread in the toaster for 1 minute. Remove from toaster and
         apply butter to each piece."


        When the test is run, this data gets loaded into the recipes table and is available within the test. The tests you currently
        have in your test don’t need these fixtures, but you may write future tests that depend on having data in the test
        database. For example, you may want to write a test to make sure that there can only be one recipe called “Toast”.
        That test might look something like this:

           1    def test_should_only_have_one_recipe_called_toast




Copyright 2009 Brian P. Hogan                                                                                                                  11
Validating User Input

              2       @recipe = Recipe.new(:title =>"Toast")
              3       @recipe.valid?
              4       Assert @recipe.errors.on(:title).include?("must be unique")
              5     end




       2.3. Running the Test
           To run the test, we need to first prepare the test database. We do that by running a rake task.

           rake db:test:clone

           This task takes the structures from our development database and creates a new test database that we can use over
           and over again.

            Our test is actually a standalone Ruby application. We can run the test directly using Ruby.

           ruby -Ilib:test testunitrecipe_test.rb1

           Everything should work well. You should get no errors or failures.

                             Note

                             You can run all of the unit tests by running rake test:units. This also takes care of initializing
                             the test database for you.



    3. Providing Feedback to Users
       Now that we know our validation works, we should see what it looks like when users attempt to leave fields blank.

       Active Record’s Validations places error messages in an array which can be accessed by a helper method in a view.
       The helper method error_messages_for takes in an instance of an Active Record model and attempts to display the
       error messages in a nice friendly manner. Built in helper methods for text boxes, select boxes, and text areas also
       are validation-aware. They will become styled automatically, providing additional visual cues. The styles are applied
       using CSS, so you can modify the way they look. Take a look at Figure 3.1, “User Feedback as provided by Rails
       validations” [13] to see the results.




1
 The -Ilib: argument tells Ruby what folder it should look in to load additional files. Our test case above requires a file called 'test_helper' which is located
in the test folder.




Copyright 2009 Brian P. Hogan                                                                                                                                       12
Validating User Input

     Figure 3.1. User Feedback as provided by Rails validations




     This task alone could take a web developer a few hours to get right. We’ve created a working solution with a unit test
     in only a few minutes. These validations work for new entries and existing entries.

     There are numerous plugins available for Rails to change how validation works at the web page level. Most plugins are
     available at http://www.agilewebdevelopment.com/plugins




Copyright 2009 Brian P. Hogan                                                                                                 13
Cleaning Up the Scaffolding


Chapter 4. Cleaning Up the Scaffolding
     As stated before, the scaffolding needs some work before it can be used in production. As you become more familiar
     with the way Rails works, you may find yourself relying less and less on scaffolding to create your pages.


  1. Cleaning up the List page
     The list page is pretty good for starters, but one thing that’s kinda rough about it is that it requires Javascript to be
     enabled in order to delete records! Yuck!.

     It might be nice to show just the recipe name and when it was last updated instead of the ingredients and instructions.
     Remember, the list page is built using whatever fields you specified in your scaffold command.

     Replace the contents of the page views/recipes/index.erb.html with the following code:

       1   <h1>Listing recipes</h1>
       2
       3   <table>
       4     <tr>
       5       <th>Title</th>
       6       <th>Last Updated</th>
       7       <th colspan="2">&nbsp;</th>
       8     </tr>
       9
      10   <% for recipe in @recipes %>
      11     <tr>
      12       <td><%= link_to h(recipe.title), recipe %></td>
      13       <td><%= time_ago_in_words recipe.updated_at %> ago</td>
      14       <td><%= link_to 'Edit', edit_recipe_path(recipe) %></td>
      15       <td><%= button_to 'Destroy', recipe, :confirm => 'Are you sure?', :method => :delete %></
     td>
      16     </tr>
      17   <% end %>
      18   </table>
      19
      20   <br />
      21
      22   <%= link_to 'New recipe', new_recipe_path %>


     Refresh the index page in your browser. Your new page should resemble something like the one in Figure 4.1, “The
     modified Index page” [15].

                    The h() method

                    The h() method sanitizes strings. It will escape any Javascript that someone might have tried to enter.
                    There are other ways to sanitize values entered by your users, but this is the simplest; you just have to
                    remember to use it!




Copyright 2009 Brian P. Hogan                                                                                                    14
Cleaning Up the Scaffolding


        Links in Rails

        Rails makes it easy to link resources. The link_to helper builds links to internal or external resources easily.

        To create a link to Google, you simple use link_to "Google", "http://www.google.com".

        We generated our controllers and views using scaffolding so you haven't had much of a chance to see the code
        yet, but each view is generally associated with a controller action. For example, we can build a link to the "New
        Recipe" form by creating a link to the "new" action of the "recpies" controller like this:

        link_to "New Recipe", :controller => "recipes", :action => "new"

        However, Rails is all about conventions. When we generated the scaffold, the file routes.rb was modified to
        define a resource. This definition creates some helper methods that make making links incredibly easy.

        We can create a link to the new recipes page like this:

        link_to "New recipe", new_recipe_path

        We can also create a link to the list of recipes like this:

        link_to "Recipes", recipes_path

        If we have a recipe object, we can use that recipe object to build a link.

        link_to recipe.title, recipe_path(recipe) or

        link_to recipe.title, recipe.

        URLS for forms use the same convention. It's incredibly handy and one of the nicer features of the framework.


     Figure 4.1. The modified Index page




     1.1. Helpers
        Rails provides many helper methods to make displaying pages easier. This example shows a few helpers:

        • link_to : Used to create a hyperlink. We use this because Rails can manage links for us so we don’t need to
          worry about relative or absolute paths. Rails has a routing system that makes linking things together a snap.

        • h : This simple helper escapes HTML and Javascript. It helps to sanitize output, in case someone put malicious
          JavaScript into one of your input fields.



Copyright 2009 Brian P. Hogan                                                                                               15
Cleaning Up the Scaffolding

           • time_ago_in_words : This method takes a time and tells you in words how long ago it was. This is how we
             get those neat “posted five minutes ago” messages on blogs.

           The Rails documentation 1 has more information on helpers.


               Why button_to instead of link_to

               Notice that the delete feature is a button now instead of links? For safety reasons, we want all links to destructive
               actions like deletes to be called via post methods. The button_to tag does this for us. We can then style it using
               CSS so it looks nicer later on.



    2. Cleaning up the Show page
       Take a look at app/controller/recipes_controller.rb and find the show section

          1     def show
          2       @recipe = Recipe.find(params[:id])
          3     end


       This code retrieves the recipe from the database. The id sent via the url is sent to the database. This actually generates
       the sql statement “select * from recipes where id = 1”. The find method is a class method of Recipe and returns an
       instance of a recipe object. Models in Active Record handle the retrieval and representation of the data.

       Here we see that it stores the resulting Recipe instance into an instance variable (The @ means instance variable in
       Ruby.) The instance variable is passed on to the show.html.erb file. Knowing that, we can easily display the information
       about our recipe.

       Open app/views/recipe/show.html.erb and replace the contents with

          1   <h2><%=h @recipe.title %> [<%= link_to 'Edit', edit_recipe_path(@recipe) %> ]</h2>
          2
          3   <h3>Ingredients:</h3>
          4   <p><%=h @recipe.ingredients %></p>
          5
          6   <h3>Instructions</h3>
          7   <p><%=h @recipe.instructions %></p>
          8
          9   <%= link_to 'Back', recipes_path %>


       Your page should look something like Figure 4.2, “The Show Page” [16]

       Figure 4.2. The Show Page




1
 http://api.rubyonrails.com/




Copyright 2009 Brian P. Hogan                                                                                                          16
Cleaning Up the Scaffolding


  3. Using Partials to share common code
     The New and Edit forms are virtually identical except for their headings. The actual form could be shared across both
     files using a partial which is similar to an include file in PHP.. This way, if you add a field to the form, you only need
     to add it to one file instead of two.

     Create a new file in app/views/recipes called _form.html.erb. The filename should begin with an under-
     score because that’s how Rails distinguishes partials from regular views. Open up the new.html.erb file and find
     this code:

       1             <p>
       2        <%=   f.label :title %><br />
       3        <%=   f.text_field :title %>
       4      </p>
       5      <p>
       6        <%=   f.label :ingredients %><br />
       7        <%=   f.text_area :ingredients %>
       8      </p>
       9      <p>
      10        <%=   f.label :instructions %><br />
      11        <%=   f.text_area :instructions %>
      12      </p>


     Copy that code to your clipboard and paste it into _form.html.erb. Once it's pasted, remove the code from the
     new.html.erb file.. Open edit.html.erb and locate the same code. Remove it from the file.

     Now add this line to edit.html.erb, in place of the code you just removed:

       1 <%= render :partial =>"form", :locals=>{:f => f} %>


     The :locals => {:f => f} option allows you to pass variables into the partial. Since the variable f for the
     form is a local variable, it needs to be passed to the partial so the partial can “see” it and access it.

     The edit.html.erb file should now look like this:

       1   <h1>Editing recipe</h1>
       2
       3   <%= error_messages_for :recipe %>
       4
       5   <% form_for(@recipe) do |f| %>
       6
       7    <%= render :partial =>"form", :locals=>{:f => f} %>
       8
       9     <p>
      10       <%= f.submit "Update" %>
      11     </p>
      12   <% end %>
      13
      14   <%= link_to 'Show', @recipe %> |
      15   <%= link_to 'Back', recipes_path %>


     Add the same line of code to new.html.erb. in place of the code you previously removed. You’re now sharing code
     between two views using a partial.


  4. Where’s the rest of my HTML?
     You’ve probably noticed that our view pages have not included any required HTML elements, nor have they mentioned
     anything about a style sheet. Yet we can see styles being rendered and we see a lot of HTML markup if we view the
     source. Where’s this coming from?



Copyright 2009 Brian P. Hogan                                                                                                     17
Cleaning Up the Scaffolding

     Rails has a wonderfully complex yet simple template mechanism. Look in the app/vies/layout folder and you’ll
     see a file called recipes.html.erb. This file was created during your scaffold operation and is automatically linked
     to the recipes controller.

     This file wraps any view files you render from within the recipes controller. If you want one single layout for your entire
     application, you can rename this file to application.html.erb and every controller will use it.

     This file can use any instance variables (those ones prefixed with @) set in the controller, including variables created
     within the view files themselves, because it is read last before being sent to the browser. This means you can set the
     page title in the individual controller actions or even in the .erb files themselves.




Copyright 2009 Brian P. Hogan                                                                                                      18
Adding Categories


Chapter 5. Adding Categories
     A recipe should be able to be categorized. For this example, we’ll just say that a recipe can only belong to one category,
     and a category can have many recipes. We’ll say it that way because that’s how Active Record allows us to express
     relationships.


  1. Create a category model and table
     We don’t need to create a full interface to manage categories at this time, so create the new model by dropping to a
     command prompt and typing

     ruby script/generate model Category name:string

     Run the newly-created migration by executing the command rake db:migrate from the command line. It will
     create the new table.


  2. Adding some default records with Rake
     Sometimes it’s nice to have your database pre-populated with records. You saw how fixtures can do that with test data,
     but that’s not always a good choice. Migrations could be used to insert data into your database but that can be volatile
     as well. The best approach is to use rake, which is the same tool you’ve been using to run your migrations.

     Rake is an automation language. To use it, you simply create a file with some tasks and then execute it via the rake
     command.

     Rails projects look for Rake tasks in files with the .rake extension in the project’s lib/tasks folder. Create a new
     file in that folder called import.rake. Place this code in the file:

       1      namespace :db do
       2
       3         desc "Puts default categories in the database"
       4         task :import_categories => :environment do
       5
       6            Category.create    :name   =>"Beverages"
       7            Category.create    :name   =>"Deserts"
       8            Category.create    :name   =>"Appetizers"
       9            Category.create    :name   =>"Entrees"
      10            Category.create    :name   =>"Breakfast"
      11            Category.create    :name   =>"Sandwiches"
      12
      13        end
      14      end


     A namespace is just a container for code like in any other language. When you issued the command rake db:migrate
     you called the migrate task within the db namespace. We’ll follow that same convention here.

     To import the records into your database ,issue the command

     rake db:import_categories


  3. Modifying the Recipes table
     Since we want to have a relationship between categories and recipes, we have to place a foreign key in the recipes table
     so it can be associated with a recipe. We’ll do this with a migration too.



Copyright 2009 Brian P. Hogan                                                                                                     19
Adding Categories

     Create a new migration. From the command line, execute the command

     ruby script/generate migration add_category_id_to_recipes

     This will create a new migration file db/migrate/XXXXXXX_add_category_id_to_recipes.rb. Open the
     file and replace it with the following code:

       1    class RecipeCategory < ActiveRecord::Migration
       2      def self.up
       3        add_column :recipes, :category_id, :integer
       4      end
       5
       6      def self.down
       7        remove_column :recipes, :category_id
       8      end
       9    end


     Run the migration to alter the database. (rake db:migrate).

     At this point you will need to stop and restart your web server. This is only necessary with SQLite3, and only because you
     changed a table's structure.. Other databases can be modified without restarting the web server. Press CTRL+BREAK
     to stop Mongrel and then restart it by executing the command

     ruby script/server


  4. Creating an Association Between a Recipe and
  a Category
     Associations allow objects to interact. Associations are methods that map the primary keys of one table to the foreign
     keys of another; the relational mapping part of “object-relational mapping”.

     Open app/models/recipe.rb and modify its contents with the following code:

       1    class Recipe &lt; ActiveRecord::Base
       2      belongs_to :category
       3      validates_presence_of :title, :ingredients, :instructions
       4    end
       5


     The belongs_to class method takes in a symbol name of a class with which we wish to associate. Rails needs no
     further information because it will assume that :category references a class called Category, that the table name will
     be categories, and that this table (recipes) has a foreign key column called category_id that will reference the id
     column in the categories table. Of course, we can override these assumptions, but it’s easier just to follow convention.

     This association adds some new methods to an instance of Recipe. We can now access the name of the category directly
     through the recipe.

     recipe = Recipe.find(1)  # gets recipe with id of 1
     recipe.category.name # gets the associated category name



     4.1. Lazy vs. Eager Loading
        The above code will do the retrieval using lazy loading, meaning that two SQL statements will be called. This could
        be bad if we were retrieving all recipes and displaying the category for each one. If you have 200 recipes, the above
        code would generate 201 SQL statements!



Copyright 2009 Brian P. Hogan                                                                                                     20
Adding Categories

        Thankfully there is a solution for situations like this… eager loading. Rails will generate proper left joins for us if
        we specify the objects to include.

        recipe = Recipe.find(1)


        becomes

        recipe = Recipe.find(1, :include => [:category])


        and now only one statement is sent to the database.


  5. Adding categories to the controllers and views
     In order to add the category selection to the forms and views, we need to do some work in the controller.


     5.1. The New and Edit forms
        Open app/controller/recipes_controller.rb and locate the new method. Modify it so it retrieves the
        categories into an instance variable called @categories. Remember that a controller’s instance variables are then
        accessible in the view pages.

          1       def new
          2         @categories = Category.all
          3         @recipe = Recipe.new
          4         respond_to do |format|
          5             format.html # new.html.erb
          6             format.xml { render :xml => @recipe }
          7           end
          8       end


        Now find the edit method and modify it so it also retrieves the categories into @categories.

          1       def edit
          2         @categories = Category.all
          3         @recipe = Recipe.find(params[:id])
          4       end


        Open app/views/recipes/_form.html.erb and add the following block at the end of the file:

          1 <p>
          2             <%= f.label :category_id %><br />
          3             <%= f.select :category_id, @categories.collect{|c| [c.name,
         c.id] }, :include_blank => true %>
          4           </p>


        This code adds a select box which will contain all of the categories so that your users can place a recipe into the
        category chosen by the dropdown. This is an example of the select helper.

        The collect method iterates through all the categories and returns an array. In this case we’re returning an array
        of arrays which the select helper can use to build the form. This is an example of a block and you’ll see lots of these
        in Rails applications and Ruby code.

        We’re also including a blank option so that a user doesn’t have a category already selected when they view the page.



Copyright 2009 Brian P. Hogan                                                                                                     21
Adding Categories


     5.2. The Show view
        When we display a recipe, we want to now show the category for the recipe. We can do that easily thanks to the way
        the belongs_to association works. When we associated a category to a recipe using that association, it added a
        method to our Recipe model called category, which returns an instance of the associated category record.

        Locate the show action in recipes_controller and add eager loading for the category using the :include
        option for find.

          1      def show
          2        @recipe = Recipe.find(params[:id], :include=>[:category])
          3        respond_to do |format|
          4          format.html # show.html.erb
          5          format.xml { render :xml => @recipe }
          6        end
          7      end


        Open app/views/recipes/show.html.erb and add

        <p>Category: <%= h(@recipe.category.name) rescue “No category found” %></p>


        somewhere on the page. When you refresh, you'll see the category displayed.

                       Tip

                       The rescue statement catches a possible exception that could be thrown if the recipe does not yet have
                       an assigned category. Your recipes don't all have the category assigned yet, and without this rescue
                       statement, this page would fail to render.


     5.3. The List view
        Find the index action in recipes_controller.rb and add the :include option to the find to eager-load
        the category information just like the previous example.

          1      def index
          2        @recipes = Recipe.all :include => [:category]
          3        respond_to do |format|
          4          format.html # index.html.erb
          5          format.xml { render :xml => @recipes }
          6        end
          7
          8      end


        Open app/views/recipes/index.html.erb and modify it so you can see the category name in the table. You’ll need to
        add a column heading as well as the data cell itself. Remember to use the association to retrieve the category name
        just like you did on the show page!


  6. Test it out
     With the associations in place and the views fixed up, go ahead and play with your application. Notice how you can
     now add categories to your recipes, and when you edit an existing recipe, its associated category automatically shows
     up in the dropdown list.




Copyright 2009 Brian P. Hogan                                                                                                   22
Other Rails Tidbits


Chapter 6. Other Rails Tidbits
     There's a lot more to the Rails framework than what we covered here. Let's explore a few other features.


  1. Writing Documentation with RDoc
     Documenting code is one of the most useful things a developer can do. Unfortunately it’s often done poorly if it’s even
     done at all.

     Ruby on Rails aims to change how developers write documentation by making use of RDoc. RDoc is a program that can
     parse Ruby files for comments and convert these comments to HTML pages or other formats. It generates very clean
     and nice-looking documentation and is so easy to use that developers quickly come to actually enjoying documentation.

     Any comments located directly above a class or method declaration will be interpreted by the RDOC parser to be the
     comments for that given block of code.

     Here’s an example of some commented code.

        1   #=Recipes
        2   # Recipes are added, removed, maintained, and viewed using
        3   # the actions in this controller.
        4   #==Authentication
        5   # There is no authentication on this controller
        6   class RecipesController < ApplicationController
        7
        8    # This action handles the default document (Index) and
        9    # simply redirects users to the list action.
       10    def index
       11      list
       12      render :action => 'list'
       13    end
       14
       15   end


      When we run the command rake doc:app, our HTML documentation will be created for us. See Figure 6.1, “RDoc
     output in HTML” [23]

     Figure 6.1. RDoc output in HTML




Copyright 2009 Brian P. Hogan                                                                                                  23
Other Rails Tidbits


  2. Annotating Models
     One of the things that can get confusing with Rails is the fact that the models don’t have much code. Because the
     methods are generated for you, you can’t look at a model and tell what database fields you refer to unless you were
     to comment them yourself.

     Thankfully we can handle this simply by installing a plugin called annotate_models written by the creator of RDoc,
     Dave Thomas. Install the plugin by executing this command from the command line

     ruby     script/plugin                    install          http://repo.pragprog.com/svn/Public/plug-
     ins/annotate_models

                      Note

                      You’ll need to have the Subversion client tools installed on your machine for this to work and the svn
                      command needs to be on your path. Visit http://subversion.tigris.org/servlets/Pro-
                      jectDocumentList?folderID=91 to get the latest version if you don't have it..

                      After installation, be sure to close any open command prompt windows. Then re-open your command
                      prompt window and navigate back to the root of your project.)

     Once installed, run the command

     rake annotate_models

     Your models will now be commented with the schema definition. This will then be placed in your documentation the
     next time you generate your docs. You can see the output in Figure 6.2, “Annotations added to a model” [24]

     Figure 6.2. Annotations added to a model

        1
        2             # == Schema Information
        3             # Schema version: 20090419074728
        4             #
        5             # Table name: recipes
        6             #
        7             # id            :integer         not null, primary key
        8             # title         :string(255)
        9             # ingredients :text
       10             # instructions :text
       11             # created_at    :datetime
       12             # updated_at    :datetime
       13             # category_id :integer
       14             #
       15
       16             class Recipe < ActiveRecord::Base
       17               belongs_to :category
       18               validates_presence_of :title, :ingredients, :instructions
       19             end
       20
       21
       22



  3. Debugging and Exploring with Console
     One of the ways you can debug a Rails application is with unit tests. However, often times you might not know what
     to write. That’s where console comes in. Console lets you load the entire Rails application into the Interactive Ruby
     environment so you can execute commands and interact with your application.




Copyright 2009 Brian P. Hogan                                                                                                  24
Other Rails Tidbits

     From the root of your project, execute the command

     ruby script/console

     to enter the console. Once the console is loaded, you can start experimenting with your objects, as shown in Figure 6.3,
     “Using the Rails Console to work with objects” [25]

     Figure 6.3. Using the Rails Console to work with objects


        Loading development environment (Rails 2.3.2)
        >> recipe = Recipe.create :title => "test", :ingredients => "stuff", :instructions => "mix
       together"
        => #<Recipe id: 2, title: "test", ingredients: "stuff", instructions: "mix together",
       created_at: "2009-04-19 08:21:03", updated_at: "2009-04-19 08:21:03", category_id: nil>
        >> id = recipe.id
        => 2
        >> recipe.category
        => nil
        >> category = Category.find_by_name "Sandwiches"
        => #<Category id: 6, name: "Sandwiches", created_at: "2009-04-19 07:50:00", updated_at:
       "2009-04-19 07:50:00">
        >> recipe.category = category
        >> recipe.changed
        => ["category_id"]
        >> recipe.save
        => true
        >> exit



     In the above example, I use the console to create a new recipe and save it to the database. I then retrieve the id for the
     recipe. Then I use the find method on Recipe to locate the recipe again. Then I see if it has a category. Of course, it
     doesn’t so I fetch a category from the database and assign it to my instance. I use the changed method to see what
     columns in the database have changed. The association is not saved until I execute the save method of my instance.

     This is just the beginning, but it shows how you can use the console to learn more about how the methods on the classes
     work without having to write any view pages or controller code.


  4. Logging
     Rails applications automatically log requests and responses to the various logs. One log you should really keep an eye
     on is your development.log file. It contains a lot of useful information such as the parameters sent on each request as
     well as the SQL statements created by Rails and sent to the database.

     This is the place you’ll want to look to tune your application. Not only can you see if you’re executing too many SQL
     statements for the job at hand, but you can also see how long it took Rails to serve the request to your client.


  5. Writing your own SQL statements
     At first glance, Rails may seem limited. We’ve gone through this entire project without writing any SQL. A lot of the time
     we won’t have to worry about it. However, it is still very possible for us to get into the code and do what we need to do.

     For example, one of the methods in Active Record is called find_by_sql which allows us to look records up using
     our own custom SQL statement.

        @results = Recipe.find_by_sql "select r.title, c.name
                                       from recipes r




Copyright 2009 Brian P. Hogan                                                                                                     25
Other Rails Tidbits

                                                join categories c
                                                on r.category_id = c.id"


        => [#<Recipe:0x3750478 @attributes={"name"=>"Beverages", "title"=>"Test"}>]


     You have to understand Ruby to understand what this example returns, so I’ll help out. The square brackets ([]) sur-
     rounding the result means that you're dealing with an Array. The #<Recipe piece means it’s a Recipe object. So
     when you use the find_by_sql method, you receive an array of objects which you can then iterate over.

        @results.each do |recipe|
            puts recipe.name # print to STDOUT
            puts recipe.title # print to STDOUT
        end


     Note that a new method title has been created in the instance of the class. Active Record inspected the column names
     that came back from the database and dynamically created accessor methods for us to use.

                      Warning

                      Never use “puts” in your Rails application directly. It can cause problems that you may not find later on.
                      It’s only to be used in tests and in the console to help you debug. If you’re wondering, it’s equivalent to
                      system.out.println or echo.

     There are many other features in Rails that make it extremely flexible. Don’t get fooled by the hype about ORM and
     scaffolding. Rails is much more than that!




Copyright 2009 Brian P. Hogan                                                                                                       26
Development and Deployment


Chapter 7. Development and Deployment

    1. Exploring Development Tools
      There are several different tools you can use to easily build Rails applications.

      • If you’re on a Mac, you have to check out TextMate. While not an IDE, it is built with Rails development in mind
        and is just a dream to work with when you see it. It’s the featured editor in all of the Rails screencasts. See http://
        macromates.com/ for more information.

      • Those interested in a full-blown IDE for Rails development will love NetBeans Ruby IDE from Sun (yup, the Java
        guys). Snag your copy at http://download.netbeans.org/netbeans/6.0/final/ and be sure to grab the one for Ruby. You
        will need the Java SDK as well to run this, but it’s worth it.

      • Windows users absolutely need to look at Ruby In Steel. There's a free version available at http://
        www.sapphiresteel.com/Ruby-In-Steel-New-Free-Edition that actually includes pretty much everything you need to
        get started with Rails.

      • Advanced users will definitely want to look at vim with the rails.vim plugin.

         Rails.vim plugin: http://www.vim.org/scripts/script.php?script_id=1567



    2. Deploying Rails Applications
      Deploying Rails applications is no trivial task. Rails applications require more setup work than PHP applications and
      there are lots of things that can go wrong when you’re first starting out. Do not attempt deployment until you are very
      comfortable with the Rails framework.

      Applications can be deployed using a variety of methods, but the most popular method is to use Passenger. Passenger
      works with Apache or Nginx to make deploying Rails applications extremely easy. The Passenger site1 provides more
      information on deploying applications using this method. Another excellent method for deployment is Apache or Ng-
      inx balancing a collection of Mongrel server instances, however this method is expected to be abandoned in favor of
      Passenger.

      There are many web hosting companies that support Rails Shared hosts such as Dreamhost, RailsPlayground, and Blue-
      host keep the cost low by sharing space and memory with other users. This is a great low-cost way to launch your
      application.

      If you need high availability, you can look at RailsMachine and EngineYard, two solutions that promise to host large
      Rails sites with ease. They are significantly more expensive than shared hosting plans. EngineYard is incredible, but
      you can’t afford it unless you are really making money. It’s worth every penny though and they do offer a Solo plan
      using Amazon's EC2 cloud.

      If you just want to set things up yourself on dedicated virtual servers, you could look at Slicehost, Linode [http://
      www.linode.com/], and Rimuhosting [http://www.rimuhosting.com/]. Rimuhosting provides good support for Rails on
      their virtual servers, as does Linode.

      Deploying applications is not trivial, but it's not a terrible experience either. Once you've gotten your head around how
      it all works, you'll have no problem moving apps around.
1
 http://www.modrails.com/




Copyright 2009 Brian P. Hogan                                                                                                     27
Development and Deployment

     More information on deployment can be found in the book Deploying Rails Applications from the Pragmatic Bookshelf,
     including a section on deploying on Windows, written by your humble author.




Copyright 2009 Brian P. Hogan                                                                                             28
Homework and Exploration


Chapter 8. Homework and Exploration
     If you want to take the exercise further, you can try some of the ideas below. The answers are not provided but the
     solutions for each problem can be found by looking at similar exercises in the preceding tutorial.

     1. Document some other methods in your controllers and models and then regenerate the docs. Here are some simple
        formatting symbols:

        • # is the comment

        • = is a large header

        • == is a level 2 header

        • --- is a horizontal rule

        • * is a bullet

     2. Create a has_many association from Category to :recipes

        • Write a unit test that tests this relationship. (You’ll need to make fixtures for categories and recipes and you’ll
          need to load both of these in the test file.)

        • See http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html for details on has_many

     3. Create a controller and views to manage the categories. Use the recipe controller and views as an example. If you
        choose to scaffold this, you may need to undo some work you’ve done so be careful. It’s easier to write it by hand.

        • When you display a category, display the recipes associated with that category, making use of the has_many
          association you created.

        • On the Show page for a recipe, make a link to the category


                          <%=link_to @recpie.category, show_category(@recipe.category) %>




     4. Extra Credit: When a category is deleted, set all associated recipes to a nil category using a before_destroy ActiveRe-
        cord callback.




Copyright 2009 Brian P. Hogan                                                                                                     29
Where To Go Next?


Chapter 9. Where To Go Next?
     Hopefully this exercise gave you enough of an overview of the Ruby on Rails framework to see the potential impact it
     has on rapid application development. From here, you should be able to extend this assignment by doing the homework
     or explore further by coming up with your own application, using this as a model.


  1. Books
     • Learn to Program (Chris Pine)

       http://www.pragprog.com/titles/fr_ltp/learn-to-program

     • Agile Web Development with Rails (Dave Thomas)

       http://www.pragprog.com/titles/rails3/agile-web-development-with-rails-third-edition

     • Ruby for Rails (David A. Black)

       http://www.manning.com/black/

     • Programming Ruby (Dave Thomas)

       http://www.pragprog.com/titles/ruby/programming-ruby       or     older   version   online   for   free   at   http://
       www.rubycentral.com/book/

     • Deploying Rails Applications (Ezra Zygmuntowicz, Bruce Tate, Clinton Begin, Geoffrey Grosenbach, and Brian
       Hogan)

       http://www.pragprog.com/titles/fr_deploy/deploying-rails-applications

     • Rails for .Net Developers (Jeff Cohen and Brian Eng)

       http://www.pragprog.com/titles/cerailn/rails-for-net-developers

     • Rails for Java Developers (Stuart Halloway and Justin Gehtland)

       http://www.pragprog.com/titles/fr_r4j/rails-for-java-developers

     • Rails for PHP Developers (by Derek DeVries and Mike Naberezny)

       http://www.pragprog.com/titles/ndphpr/rails-for-php-developers

     • The Rails Way (Obie Fernandez)

       http://www.amazon.com/Rails-Way-Addison-Wesley-Professional-Ruby/dp/0321445619


  2. Online Resources
     • Ruby on Rails Discussion group (http://groups.google.com/group/rubyonrails-talk)

     • #rubyonrails IRC channel (http://wiki.rubyonrails.org/rails/pages/IRC)

     • Peepcode (http://peepcode.com/)

     • Railscasts (http://railscasts.com/)



Copyright 2009 Brian P. Hogan                                                                                                   30
Where To Go Next?

     • Railsforum (http://www.railsforum.com/)




Copyright 2009 Brian P. Hogan                    31
Index

                                                database reflection, 8
Index                                           dynamic method creation, 9

, 15                                        P
                                            Partials, 2
A                                              sharing code with, 17
accessor, 9
Array, 26                                   R
Associations                                rake
   belongs_to, 20                              loading data with, 19
   eager loading, 20                        Rake tasks
                                               Cloning the test database from the development database, 12
C                                           RDoc, 23
                                               example, 23
Console
                                               Generating documentation, 23
  debugging, 25
                                            Refactoring, 2
Controllers, 1
                                            Rubygems
                                               Gems, 3
D
data
   populating database with seed data, 19
                                            S
                                            Scaffolding, 6
database.yml, 4
                                               issues with, 7
Deploying, 27
                                            script/server, 8
development environments, 27
                                            SQL
Documentation
                                               statements in the Rails logs, 25
   Annotating Models with schema info, 24
                                               writing your own, 25
   generating documentation with RDOC, 23
                                            SQLite3
                                               automatic creation, 5
E                                              installation of, 5
Exception Handling                          Symbols, 9
  rescue, 22
                                            T
F                                           Test-driven development
Fixtures, 11                                  TDD, 2
                                            Tests
G                                             running a single test, 12
Generators, 6                                 running all unit tests, 12
  scaffold, 6
                                            U
H                                           Unit Tests, 10, 11
Helper methods                                running, 12
  link_to, 15
Helpers, 2                                  V
                                            Validations, 9
L                                             validates_presence_of, 9
Layouts, 2                                  Views, 1
Links, 15                                     displaying errors, 12
logging, 25                                   master layout, 17

M
Migrations, 7
  running, 8
Model-View-Controller pattern, 1
Models, 1



Copyright 2009 Brian P. Hogan                                                                          32

More Related Content

What's hot

Ug recording excelmacros
Ug recording excelmacrosUg recording excelmacros
Ug recording excelmacrosHarry Adnan
 
The MySQL Cluster API Developer Guide
The MySQL Cluster API Developer GuideThe MySQL Cluster API Developer Guide
The MySQL Cluster API Developer Guidewebhostingguy
 
Hp man ppm9.20_whats_new_pdf
Hp man ppm9.20_whats_new_pdfHp man ppm9.20_whats_new_pdf
Hp man ppm9.20_whats_new_pdfugunal
 
First7124911 visual-cpp-and-mfc-programming
First7124911 visual-cpp-and-mfc-programmingFirst7124911 visual-cpp-and-mfc-programming
First7124911 visual-cpp-and-mfc-programmingxmeszeus
 
Parallels Plesk Panel 9 Reseller's Guide
Parallels Plesk Panel 9 Reseller's GuideParallels Plesk Panel 9 Reseller's Guide
Parallels Plesk Panel 9 Reseller's Guidewebhostingguy
 
OfficeReports Manual
OfficeReports ManualOfficeReports Manual
OfficeReports ManualOfficeReports
 
Mvc music store tutorial - v3.0
Mvc music store   tutorial - v3.0Mvc music store   tutorial - v3.0
Mvc music store tutorial - v3.0jackmilesdvo
 
Mvc music store tutorial - v3.0 (1)
Mvc music store   tutorial - v3.0 (1)Mvc music store   tutorial - v3.0 (1)
Mvc music store tutorial - v3.0 (1)novia80
 
Mvc music store tutorial - v2.0
Mvc music store   tutorial - v2.0Mvc music store   tutorial - v2.0
Mvc music store tutorial - v2.0Jhosep Kingman
 
Test and target book
Test and target bookTest and target book
Test and target bookMesurex
 
Data source integration guide for HP Performance Agent
Data source integration guide for HP Performance AgentData source integration guide for HP Performance Agent
Data source integration guide for HP Performance Agenthernajes
 
TopStyle Help &amp; &lt;b>Tutorial&lt;/b>
TopStyle Help &amp; &lt;b>Tutorial&lt;/b>TopStyle Help &amp; &lt;b>Tutorial&lt;/b>
TopStyle Help &amp; &lt;b>Tutorial&lt;/b>tutorialsruby
 
W java81
W java81W java81
W java81rasikow
 

What's hot (18)

Ug recording excelmacros
Ug recording excelmacrosUg recording excelmacros
Ug recording excelmacros
 
The MySQL Cluster API Developer Guide
The MySQL Cluster API Developer GuideThe MySQL Cluster API Developer Guide
The MySQL Cluster API Developer Guide
 
Hp man ppm9.20_whats_new_pdf
Hp man ppm9.20_whats_new_pdfHp man ppm9.20_whats_new_pdf
Hp man ppm9.20_whats_new_pdf
 
First7124911 visual-cpp-and-mfc-programming
First7124911 visual-cpp-and-mfc-programmingFirst7124911 visual-cpp-and-mfc-programming
First7124911 visual-cpp-and-mfc-programming
 
Parallels Plesk Panel 9 Reseller's Guide
Parallels Plesk Panel 9 Reseller's GuideParallels Plesk Panel 9 Reseller's Guide
Parallels Plesk Panel 9 Reseller's Guide
 
OfficeReports Manual
OfficeReports ManualOfficeReports Manual
OfficeReports Manual
 
Mvc music store tutorial - v3.0
Mvc music store   tutorial - v3.0Mvc music store   tutorial - v3.0
Mvc music store tutorial - v3.0
 
Mvc music store tutorial - v3.0 (1)
Mvc music store   tutorial - v3.0 (1)Mvc music store   tutorial - v3.0 (1)
Mvc music store tutorial - v3.0 (1)
 
Begining j2 me
Begining j2 meBegining j2 me
Begining j2 me
 
Linux training
Linux trainingLinux training
Linux training
 
R Ints
R IntsR Ints
R Ints
 
Mvc music store tutorial - v2.0
Mvc music store   tutorial - v2.0Mvc music store   tutorial - v2.0
Mvc music store tutorial - v2.0
 
Test and target book
Test and target bookTest and target book
Test and target book
 
Drools expert-docs
Drools expert-docsDrools expert-docs
Drools expert-docs
 
Data source integration guide for HP Performance Agent
Data source integration guide for HP Performance AgentData source integration guide for HP Performance Agent
Data source integration guide for HP Performance Agent
 
TopStyle Help &amp; &lt;b>Tutorial&lt;/b>
TopStyle Help &amp; &lt;b>Tutorial&lt;/b>TopStyle Help &amp; &lt;b>Tutorial&lt;/b>
TopStyle Help &amp; &lt;b>Tutorial&lt;/b>
 
Threading
ThreadingThreading
Threading
 
W java81
W java81W java81
W java81
 

Similar to Rails Cookbook

Hibernate Reference
Hibernate ReferenceHibernate Reference
Hibernate ReferenceSyed Shahul
 
&lt;img src="../i/r_14.png" />
&lt;img src="../i/r_14.png" />&lt;img src="../i/r_14.png" />
&lt;img src="../i/r_14.png" />tutorialsruby
 
Dimensional modelling sg247138
Dimensional modelling sg247138Dimensional modelling sg247138
Dimensional modelling sg247138Sourav Singh
 
Sg247692 Websphere Accounting Chargeback For Tuam Guide
Sg247692 Websphere Accounting Chargeback For Tuam GuideSg247692 Websphere Accounting Chargeback For Tuam Guide
Sg247692 Websphere Accounting Chargeback For Tuam Guidebrzaaap
 
Certification guide series ibm tivoli usage and accounting manager v7.1 imple...
Certification guide series ibm tivoli usage and accounting manager v7.1 imple...Certification guide series ibm tivoli usage and accounting manager v7.1 imple...
Certification guide series ibm tivoli usage and accounting manager v7.1 imple...Banking at Ho Chi Minh city
 
Uni cambridge
Uni cambridgeUni cambridge
Uni cambridgeN/A
 
Mvc music store tutorial - v3.0
Mvc music store   tutorial - v3.0Mvc music store   tutorial - v3.0
Mvc music store tutorial - v3.0mahmud467
 
Mvc music store tutorial - v3.0
Mvc music store   tutorial - v3.0Mvc music store   tutorial - v3.0
Mvc music store tutorial - v3.0lookzlook
 
Best Python tutorial (release 3.7.0)
Best Python tutorial (release 3.7.0)Best Python tutorial (release 3.7.0)
Best Python tutorial (release 3.7.0)youssef bouferdou
 
0802 python-tutorial
0802 python-tutorial0802 python-tutorial
0802 python-tutorialZahid Hasan
 

Similar to Rails Cookbook (20)

Hibernate Reference
Hibernate ReferenceHibernate Reference
Hibernate Reference
 
&lt;img src="../i/r_14.png" />
&lt;img src="../i/r_14.png" />&lt;img src="../i/r_14.png" />
&lt;img src="../i/r_14.png" />
 
Red book Blueworks Live
Red book Blueworks LiveRed book Blueworks Live
Red book Blueworks Live
 
Bwl red book
Bwl red bookBwl red book
Bwl red book
 
Dimensional modelling sg247138
Dimensional modelling sg247138Dimensional modelling sg247138
Dimensional modelling sg247138
 
Sg247692 Websphere Accounting Chargeback For Tuam Guide
Sg247692 Websphere Accounting Chargeback For Tuam GuideSg247692 Websphere Accounting Chargeback For Tuam Guide
Sg247692 Websphere Accounting Chargeback For Tuam Guide
 
Tortoise svn 1.7-en
Tortoise svn 1.7-enTortoise svn 1.7-en
Tortoise svn 1.7-en
 
Certification guide series ibm tivoli usage and accounting manager v7.1 imple...
Certification guide series ibm tivoli usage and accounting manager v7.1 imple...Certification guide series ibm tivoli usage and accounting manager v7.1 imple...
Certification guide series ibm tivoli usage and accounting manager v7.1 imple...
 
E views 9 command ref
E views 9 command refE views 9 command ref
E views 9 command ref
 
Uni cambridge
Uni cambridgeUni cambridge
Uni cambridge
 
Mvc music store tutorial - v3.0
Mvc music store   tutorial - v3.0Mvc music store   tutorial - v3.0
Mvc music store tutorial - v3.0
 
Mvc music store tutorial - v3.0
Mvc music store   tutorial - v3.0Mvc music store   tutorial - v3.0
Mvc music store tutorial - v3.0
 
Hibernate Reference
Hibernate ReferenceHibernate Reference
Hibernate Reference
 
Akeeba backup-guide
Akeeba backup-guideAkeeba backup-guide
Akeeba backup-guide
 
Hibernate reference
Hibernate referenceHibernate reference
Hibernate reference
 
Best Python tutorial (release 3.7.0)
Best Python tutorial (release 3.7.0)Best Python tutorial (release 3.7.0)
Best Python tutorial (release 3.7.0)
 
Tutorial edit
Tutorial editTutorial edit
Tutorial edit
 
0802 python-tutorial
0802 python-tutorial0802 python-tutorial
0802 python-tutorial
 
0802 python-tutorial
0802 python-tutorial0802 python-tutorial
0802 python-tutorial
 
Python everthing
Python everthingPython everthing
Python everthing
 

Recently uploaded

costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfngoud9212
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 

Recently uploaded (20)

costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdf
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort ServiceHot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 

Rails Cookbook

  • 1. The Rails Cookbook A Ruby on Rails Crash Course Brian Hogan
  • 2. The Rails Cookbook The Rails Cookbook: A Ruby on Rails Crash Course Brian Hogan Published 2008 Copyright © 2009 Brian P. Hogan Copyright 2009 Brian P. Hogan 2
  • 3. The Rails Cookbook Copyright 2009 Brian P. Hogan 3
  • 4. Dedication Dedication This book is dedicated to the Web Development students at the University of Wisconsin-Eau Claire, past, present, and future. Copyright 2009 Brian P. Hogan i
  • 5. The Rails Cookbook Table of Contents 1. Introduction ............................................................................................................................................. 1 1. Rails ............................................................................................................................................... 1 2. Basic Concepts ................................................................................................................................. 1 2.1. MVC Design Pattern ............................................................................................................... 1 2.2. Agile Programming Techniques ................................................................................................ 2 2.3. Other features and components of Rails ..................................................................................... 2 3. Installing Ruby on Rails .................................................................................................................... 3 2. Your First Rails Project - A Cookbook ......................................................................................................... 4 1. Configuring your Database ................................................................................................................. 4 1.1. Configuring the Database ......................................................................................................... 5 2. Creating the Recipes interface using Scaffolding .................................................................................... 6 2.1. Migrations ............................................................................................................................. 7 2.2. The migration file .................................................................................................................. 7 2.3. Creating the table from the migration ......................................................................................... 8 3. Test it out ....................................................................................................................................... 8 4. How did we get all that? .................................................................................................................... 8 3. Validating User Input ................................................................................................................................ 9 1. Validations ...................................................................................................................................... 9 2. Unit Tests ...................................................................................................................................... 10 2.1. How Tests Work .................................................................................................................. 11 2.2. Fixtures ............................................................................................................................... 11 2.3. Running the Test .................................................................................................................. 12 3. Providing Feedback to Users ............................................................................................................. 12 4. Cleaning Up the Scaffolding ..................................................................................................................... 14 1. Cleaning up the List page ................................................................................................................. 14 1.1. Helpers ............................................................................................................................... 15 2. Cleaning up the Show page .............................................................................................................. 16 3. Using Partials to share common code ................................................................................................. 17 4. Where’s the rest of my HTML? ......................................................................................................... 17 5. Adding Categories ................................................................................................................................... 19 1. Create a category model and table ..................................................................................................... 19 2. Adding some default records with Rake .............................................................................................. 19 3. Modifying the Recipes table ............................................................................................................. 19 4. Creating an Association Between a Recipe and a Category ..................................................................... 20 4.1. Lazy vs. Eager Loading ......................................................................................................... 20 5. Adding categories to the controllers and views ..................................................................................... 21 5.1. The New and Edit forms ........................................................................................................ 21 5.2. The Show view .................................................................................................................... 22 5.3. The List view ...................................................................................................................... 22 6. Test it out ...................................................................................................................................... 22 6. Other Rails Tidbits .................................................................................................................................. 23 1. Writing Documentation with RDoc .................................................................................................... 23 2. Annotating Models .......................................................................................................................... 24 3. Debugging and Exploring with Console .............................................................................................. 24 4. Logging ......................................................................................................................................... 25 5. Writing your own SQL statements ..................................................................................................... 25 7. Development and Deployment ................................................................................................................... 27 1. Exploring Development Tools ........................................................................................................... 27 2. Deploying Rails Applications ............................................................................................................ 27 8. Homework and Exploration ...................................................................................................................... 29 9. Where To Go Next? ................................................................................................................................ 30 1. Books ........................................................................................................................................... 30 2. Online Resources ............................................................................................................................ 30 Copyright 2009 Brian P. Hogan ii
  • 6. The Rails Cookbook Index ........................................................................................................................................................ 32 Copyright 2009 Brian P. Hogan iii
  • 7. The Rails Cookbook List of Figures 3.1. User Feedback as provided by Rails validations ......................................................................................... 13 4.1. The modified Index page ....................................................................................................................... 15 4.2. The Show Page .................................................................................................................................... 16 6.1. RDoc output in HTML .......................................................................................................................... 23 6.2. Annotations added to a model ................................................................................................................. 24 6.3. Using the Rails Console to work with objects ............................................................................................ 25 Copyright 2009 Brian P. Hogan iv
  • 8. Introduction Chapter 1. Introduction Get ready to forget everything you know about web developent, because Ruby on Rails will change your world. Web development with Ruby on Rails is one of the fastest ways to build quality applications in a fraction of the time, and all it takes is a little patience and a little time. If you've ever wanted to get started with this technology, this guide is for you. This simple yet detailed tutorial will guide you through the steps to build a working cookbook application using the Ruby on Rails framework. This guide is meant to expose you to the Rails framework and is not meant to explain all of the concepts in depth. When you’re finished with this tutorial, you will have a better understanding of the basic concepts behind Rails and you should have a basic understanding of how basic Rails applications are structured. 1. Rails Ruby on Rails is an amazing framework designed to make building high-quality, tested, stable, and scalable database- driven web applications easy. The Rails framework provides developers with the tools to create web applications using Agile programming methodologies such as rapid prototyping, test-driven development, and easy refactoring. Ruby is a dynamically-typed fully object-oriented scripting language used primarily in Japan until it drew the attention of a developer from 37Signals. The developer, David Heinemeier Hansson, was working on a new project called Basecamp. David felt very limited by the languages he was using to develop the project and so he started working with Ruby, taking advantage of all of the built-in features of the language. In July 2004, David released the Rails framework which he extracted from his work on Basecamp. Several versions later, Rails has burst onto the scene and attracted the attention of many development shops and industry leaders including Amazon, Oracle, Boeing, Thoughtworks, and many others. 2. Basic Concepts Let's take a bit and look at the basic concepts of the Rails framework. 2.1. MVC Design Pattern The MVC or Model-View-Controller pattern explicitly splits up your code and separates business logic from pre- sentation and flow control logic. It also provides mechanisms for easy reuse of code. Traditional web applications written in ASP, PHP, or ColdFusion tend to have scripts intermingled with business logic. Developers can avoid this but without a design pattern such as MVC, the process tends to be trial and error. The components of MVC Models contain all business rules and data interaction. All database-related CRUD (Create, Read, Update, and Delete) code belongs in the model as well. If this pattern is followed correctly, you’ll never write a select statement anywhere outside of the model. Instead, you will access your data by calling a method on the model. Views are what your end users will see. They are the web pages in a web application, or the user screens in a desktop application. They should contain very little presentation logic and should be optimized for reuse. Views should never interact directly with models. Controllers are the glue of the application. Controllers receive user requests, retrieve data from the models, and then send the appropriate view to the user. Copyright 2009 Brian P. Hogan 1
  • 9. Introduction Rails-specific MVC components The Rails framework divides the View layer into three separate pieces. Layouts contain your overall template and can be mapped to a controller or a specific view. Instead of placing and repeating your entire layout HTML in each view page, you centralize it in the layout. There’s no need to split a layout into various pieces like a header and footer either. This makes layouts easy to design. Helpers provide a mechanism to store presentation-related code. Helpers are very similar to a “code-behind” page. Rails comes with hundreds of pre-written helpers built in, but Rails makes it easy to define your own. This way you can avoid lots of messy logic code in your view pages. Partials are pieces of views that need to be used over and over. The web form that lets a user create a new entry might contain the same fields as the form that the user will use to update or edit that entry. Partials are used to centralize that code for easy reuse. 2.2. Agile Programming Techniques Test-driven development Test-driven development (TDD) is a programming methodology where you write tests to prove that your code actually works. In an ideal world, you will write your tests first and then write enough application code to make your tests pass. For example, a developer will create a unit test to create a new user. The test will fail until the developer actually writes the code that creates the user. The developer writes the code and continues to run the tests until they pass.. If they don’t pass, the developer knows that his or her functional code is wrong. If you write your tests first, the tests are always guaranteed to be current. New tests are added when new features are added, and tests are changed to reflect new requirements. Refactoring According to Martin Fowler, a senior consultant at Thoughtworks, the basic idea is that you make small changes to your code to improve your design, making it easier to understand and to modify. Refactoring enables you to evolve your code slowly over time, to take an iterative and incremental approach to programming. Martin's refactoring site, www.refactoring.com, is a good online resource. Rails makes refactoring easy. Because of the strict adherence to the MVC pattern, it’s trivial for experienced developers to take an entire section of an application and rewrite it without breaking the entire application. 2.3. Other features and components of Rails Generator scripts help you create Rails models, views, and controllers. Mongrel is a Ruby-based web server which is used in development and deployment so you can test your application without having to jump through deployment hoops. Runner is a script that allows you to execute your application code from outside of the Rails application. This is useful if you want to use a task scheduling program to periodically invoke some application code. Unit tests contain the code that you use to test your models. Functional tests contain code you use to test your controllers and views Copyright 2009 Brian P. Hogan 2
  • 10. Introduction Migrations allow you to define a database-agnostic schema incrementally, with the ability to roll back your changes. You can use Migrations to easily develop on SQLite, stage to MySQL, and deploy on Oracle. Plugins allow developers to add new features to the framework at almost any level. Plugins can be used to introduce new features, override existing ones, modify the Ruby core classes, or even share common models and controllers across multiple applications. Plugins are easy to write and seamless to use. They allow the Rails core team to deny many feature requests, keeping the Rails framework small and agile Rake is a Ruby program that runs user-defined tasks. Rails includes many tasks that help you manage your application. Finally, Rails provides the ability to “freeze” your application to the current version of Rails that you used for devel- opment. A simple Rake task bundles Rails with your application, ensuring that your application remains safe when the Rails framework is updated. 3. Installing Ruby on Rails Download the One Click Ruby Installer1 for Windows and run the installer, accepting all of the defaults. Next, open a command prompt and type gem update --system gem install rails gem install mongrel This will get your environment set up using the current stable release of Rails. The Gem package management tool helps you install Ruby libraries that you want to use system-wide. You have to have administrative privileges though, so if you don’t, you’ll need to have an administrator run those commands for you. Working with Older Versions of Rails This document is written with Rails 2.3.2 in mind. It is possible that the version of Rails that's currently provided by Rubygems is newer. This may cause some problems as things change rapidly with Rails and things are dep- recated or moved into plugins. However, it's easy to have multiple versions of the Rails framework installed on your machine, thanks to Rubygems. The command gem list rails will quickly tell you which versions of Rails you have installed. To install a specific version of Rails, you simply issue this command: gem install rails -v=2.3.2 To install Rails 1.2.3 in order to follow along with some older books and tutorials, install it with gem install rails -v=1.2.3 1 http://rubyforge.org/frs/download.php/47082/ruby186-27_rc2.exe Copyright 2009 Brian P. Hogan 3
  • 11. Your First Rails Project - A Cookbook Chapter 2. Your First Rails Project - A Cookbook We're going to build a simple cookbook that will let us keep track of our favorite recipes. Each recipe will have ingre- dients, instructions, and a title. Eventually you'll be able to associate a category to the recipe. Create a new Rails project by opening a command window and typing rails cookbook Generating a project using a specific Rails version If you have multiple versions of Rails installed via RubyGems, you can choose which version of Rails you wish to use for your application. For example, if you need to use Rails 2.3.2 to follow along with this book, you can install Rails 2.3.2 with gem install rails -v=2.3.2 and then create the cookbook project with rails _2.3.2_ cookbook The _2.3.2_ parameter tells RubyGems which version to use. To use Rails 1.2.3 to follow along with the famous Depot application in Agile Web Development with Rails - Second Edition, you simply create the project with rails _1.2.3_ depot That's all there is to it. This command will create the folder cookbook and place a whole bunch of framework files in that folder. As you move through this tutorial, you’ll notice that Rails has many generators that build files for you. Generators are great for file creation and laying down code that’s generic. 1. Configuring your Database Open the file config/database.yml and review the contents of the file. It should look something like this: 1 # SQLite version 3.x 2 # gem install sqlite3-ruby (not necessary on OS X Leopard) 3 development: 4 adapter: sqlite3 5 database: db/development.sqlite3 6 pool: 5 7 timeout: 5000 8 9 # Warning: The database defined as "test" will be erased and 10 # re-generated from your development database when you run "rake". 11 # Do not set this db to the same as development or production. 12 test: 13 adapter: sqlite3 14 database: db/test.sqlite3 15 pool: 5 16 timeout: 5000 17 18 production: Copyright 2009 Brian P. Hogan 4
  • 12. Your First Rails Project - A Cookbook 19 adapter: sqlite3 20 database: db/production.sqlite3 21 pool: 5 22 timeout: 5000 23 This is a YAML file. (rhymes with camel) It’s a structured configuration format that maps directly to nested hashes in Ruby and is very common for configurations in Ruby on Rails. Tabs must not be used in YAML files. Instead, two spaces are used for each indentation. Set Your Spaces Now would be a good time to ensure that the text editor you're using has soft-tabs instead of regular tabs. To ensure that your Ruby code fits in with that of other developers, you want to set your tabs to 2 spaces. • Adapter is the database adapter that we want to use. Examples are mysql, sql_server, oracle, postgresql, sqlite3, and sqlite. We’re using sqlite3 because it’s easy for beginners, requires no setup, and is the default database for a new Rails project. • Database is the name of the database. In this case, it’s the path to the database file. Other complex adapters would have you specify the database name or Oracle TNSNames entry here, and then you would have host, username, and password fields as well. 1.1. Configuring the Database With SQLite3, the database does not need to exist before we start the project; it will be created for you when you run your first migration (but don’t worry about that just yet!) Other databases like MySQL or Microsoft SQL Server require that the database (or schema) exist and that the appropriate privileges are applied. Since we’re trying to get you excited about Rails, we want to keep the momentum going. Using SQLite as a database makes it really simple to create a working rapid prototype. You can then move to a different database later, because you’ll define your database tables using pure Ruby code instead of database-specific SQL DDL statements. Installing SQLite3 on Windows 1. Download the files sqlite3.exe and sqlite3.dll and place them in your c:rubybin folder so that they are available on your path. Get sqlite3.exe from http://www.sqlite.org/sqlite-3_6_13.zip Get sqlite3.dll from http://www.sqlite.org/sqlitedll-3_6_13.zip Extract these files to c:rubybin 2. Open a command prompt and type gem install sqlite3-ruby SQLite3 is Broken on Windows To install SQLite3-ruby on Windows, simply specify version 1.2.3. gem install sqlite3-ruby -v=1.2.3 This will install a version that will work perfectly for Windows. Copyright 2009 Brian P. Hogan 5
  • 13. Your First Rails Project - A Cookbook When it finishes installing, you’re good to go! 2. Creating the Recipes interface using Scaffold- ing Since we’re writing a cookbook, the logical place to start would be with recipes. Rails uses generators to help you do some common tasks. We’ll use a generator to create a scaffold. Scaffolding is the much talked about but poorly understood feature of Rails. It’s meant to be a starting point… to give you a quick interface where you can do some simple testing and get some of the mundane repetitive code written for you. However, scaffolding can only take you so far and is not meant for use in production, hence the name “scaffolding”. There are some steps you’ll need to take to clean up the scaffolding. Let’s create a simple interface that will allow us to manage recipes in the system. The scaffold generator creates a model, controller, a set of views, and a migration, or a table definition. At the command prompt, move into your cookbook project folder cd cookbook The generate scaffold command takes several parameters. The first parameter is the model name. Model names are singular. The generator will use this model name to create a controller and a definition for a database table. Both of these, by convention, will be pluralized. The second parameter is a string that defines your database table structure. Each field can be specified along with its data type. The scaffold generator uses this information to build the web forms your users will see. They won’t be pretty but they will work. Type (all on one line) ruby script/generate scaffold recipe title:string ingredients:text instructions:text The generator runs, creating the following output: exists app/models/ exists app/controllers/ exists app/helpers/ create app/views/recipes exists app/views/layouts/ exists test/functional/ exists test/unit/ create test/unit/helpers/ exists public/stylesheets/ create app/views/recipes/index.html.erb create app/views/recipes/show.html.erb create app/views/recipes/new.html.erb create app/views/recipes/edit.html.erb create app/views/layouts/recipes.html.erb create public/stylesheets/scaffold.css create app/controllers/recipes_controller.rb create test/functional/recipes_controller_test.rb create app/helpers/recipes_helper.rb create test/unit/helpers/recipes_helper_test.rb route map.resources :recipes dependency model exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/recipe.rb create test/unit/recipe_test.rb Copyright 2009 Brian P. Hogan 6
  • 14. Your First Rails Project - A Cookbook create test/fixtures/recipes.yml create db/migrate create db/migrate/20090419054911_create_recipes.rb The generator created a recipe model, and it also created a controller called recipes_controller.rb. The con- troller will contain all of the logic that handles user requests and interacts with the models. In fact, if we look in there, it’s already written it for us! It’s got code to handle creating, editing, listing, viewing, and deleting of recipes. Because these are all common tasks, the generators can do a pretty solid job of handling this for us. One major problem with scaffolding is that it’s not dynamic. Now that we’ve generated these, we can’t rely on scaffold- ing any more. Any manual changes we make would be destroyed if we attempted to run the scaffold generator again. That means that if we change the table, we’ll need to modify the views. That’s okay though because we already have a good starting point. The model we just created requires a database table called “recipes”. Normally, you’d go and create that database table using some sort of SQL statement or visual tool. In Rails, we use migrations. 2.1. Migrations Migrations are used to modify your database. You use them to execute DDL statements against your database system. One of the best things about them is that they allow you to define your database as it changes; you can roll your changes back if they don’t work without worrying about goofing up your database. They’re also an invaluable tool when moving to production. Migrations are supported by all of the Rails database adapters. This means that you can change database systems and apply the migration to the new database which will create your structures for you. This eliminates the need to know the various dialects of data definition languages that may change across database systems. Developers can test with SQLite3, develop with MySQL, and deploy to Oracle. 2.2. The migration file Open the file dbmigrateXXXXXXXX_create_recipes.rb. The XXXXXXX part will be a numerical timestamp for the moment in time the file was created. This timestamp will help the Rails Migration system deter- mine if it's been applied, and it also allows multiple developers to modify an application's schema without creating bottlenecks. It’s contents should resemble this: 1 class CreateRecipes < ActiveRecord::Migration 2 def self.up 3 create_table :recipes do |t| 4 t.string :title 5 t.text :ingredients, :instructions 6 t.timestamps 7 end 8 end 9 10 def self.down 11 drop_table :recipes 12 end 13 end Rails uses the information in this file to create a ‘recipes’ table in the database. Note that the above definition does not include a primary key field. Unless you specify otherwise, Rails will create an ‘id’ column automatically, and will mark it as a primary key. Why is the table name “recipes” and not “recipe”? Remember that by default, Rails likes table names to be the plural form of your model. It’s pretty smart too because it can do things like person => people and category => categoies. This isn’t mandatory but if we follow these conventions, we can save a few lines of code and skip a few steps. Rails will automatically look for the recipes table when we access the Recipe model in our code. Copyright 2009 Brian P. Hogan 7
  • 15. Your First Rails Project - A Cookbook 2.3. Creating the table from the migration At this point, the table doesn’t actually exist in our database—we just have the “blueprint” for it in Ruby code. To execute the migration, we’ll run the command rake db:migrate from our command line. Run that command and you’ll see feedback stating that our recipes table was created. (in C:/rails/workspace/cookbook) == 1 CreateRecipes: migrating ================================================ -- create_table(:recipes) -> 0.0310s == 1 CreateRecipes: migrated (0.0310s) ======================================= 3. Test it out Would you believe that’s all you have to do to get a simple application written with Rails? Start the internal server and test out your application. At the command prompt, enter ruby script/server and wait a few seconds until you see that the server has in fact started. Navigate to http://localhost:3000/recipes/ and you should be able to enter a few recipes into the system. Once you’ve entered a few recipes, continue with the tutorial. The application works, but it’s a long way from good. 4. How did we get all that? When you generated the Recipe model, it created a new class that extends a class called ActiveRecord::Base. This parent class contains all of the functionality needed to create, read, update, and delete records from a database. This parent class makes all kinds of dynamic assumptions about your database connection. As we discovered before, it uses the class name (recipe) and pluralizes it to figure out what database table to use, and It uses your database.yml to find out what database server to use. The first time you access a model in a Rails application, the application connects to the associated database server and queries the database for the information about the table. It uses this information to dynamically build methods for data storage and retrieval. The Scaffold generator you ran uses that technique to build an interface that will let you create, read, update, delete, and list the rows of the recipes table. It uses the information your model has obtained and then builds HTML forms for data entry, using the data types specified by your database table’s configuration. So instead of having to write code to connect to a database and then build data entry forms, you can use the scaffolding feature of Rails as a starting point. This is just the beginning though. There's a lot more to Rails than just scaffolding an application from a single table.. In fact, most professional Rails developers don’t use scaffolding at all. Copyright 2009 Brian P. Hogan 8
  • 16. Validating User Input Chapter 3. Validating User Input You may notice that if you entered recipes into the system without filling in any fields, the data was still placed into the database. You will definitely want to require that people enter certain fields into the database. We’re going to do this with some simple validations and a simple unit test to ensure that our validations work. In Rails, validation is done in the model. This is actually good practice because the models could be used outside of the Web. The MVC pattern standard is to place all business logic and business rules in the models and have only presentation logic in the views and controllers. A word about models Our model class has very little code. In fact, it really has no code at all. As you learned earlier, its parent class does all of the work. Normally, Ruby classes use methods for accessing instance variables in a class. ActiveRecord, the ORM library used by Rails, attempts to build methods dynamically based on the metadata in your database. The class is mapped to a table and upon first use, ActiveRecord creates an instance of the class and builds the accessor methods (and many many other methods). In production mod, this reflection is only done once until the application is restarted by a server admin. Each field in our table becomes an accessor (a Ruby term meaning that it can be read and written to). For example, we said a recipe has a title. Our Recipe class will have a method called title which can be used as a getter and a setter. 1. Validations Validations are special methods provided by the Validations feature in Active Record. There are quite a few built-in methods we can use to validate data. For simplicity, we’ll use only validates_presence_of on our Recipe model. Open app/models/recipe.rb and change the contents to 1 class Recipe < ActiveRecord::Base 2 validates_presence_of :title, :ingredients, :instructions 3 end 4 Notice that we use symbols as the parameters to the validates_presence_of method. Symbols are a special type of string used in Ruby to denote a value. For now, just think of them as immutable strings. Ruby developers often use them as keys in hashes. One of the interesting things about Ruby is that methods can be defined so they take any number of parameters. In this case, the validates_presence_of method is taking in an array of symbols which represent the database fields that need to be validated. This simple line of code is all we need to make sure that users enter something for the title, ingredients, and instructions for a recipe. It’s not foolproof, but it’s a good start. If you want to see what other types of validations are out there, take a look at this page in the Rails API: http:// api.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html Copyright 2009 Brian P. Hogan 9
  • 17. Validating User Input 2. Unit Tests We need to put on the brakes here and write a quick unit test to ensure that our validation works. Unit tests are built right into the Rails framework and are designed to test the functionality of your individual models. Unit tests become vitally important to your development process because they allow you to test your business logic and prove that things are working at the model level. This way you don’t have to keep using a browser to track down bugs that aren’t related to the display. Write Tests First! Normally, we'd have written our test cases before we implemented any code. This is one reason why scaffolding is bad; it discourages you from doing the right thing. However, since you're new to Rails, we're doing things a little bit differently. Rails automatically generated a unit test skeleton for recipe when we generated the recipe model. Open the file test/ unit/recipe_test.rb and change the contents to the following: 1 require 'test_helper' 2 3 class RecipeTest < ActiveSupport::TestCase 4 5 def test_should_create_valid_record 6 recipe = Recipe.new 7 recipe.title = "Ice water" 8 recipe.ingredients = ["one glass","water","ice"].join("<br>") 9 recipe.instructions = "Combine all ingredients into the glass and let sit for two minutes. Serve immediately." 10 assert_kind_of Recipe, recipe 11 assert recipe.save 12 end 13 14 def test_should_not_save_unless_title_exists 15 recipe = Recipe.new 16 assert !recipe.save # save should fail because there are errors. 17 assert_equal "can't be blank", recipe.errors.on(:title) 18 end 19 20 def test_should_not_save_unless_ingredients_exists 21 recipe = Recipe.new 22 assert !recipe.save # save should fail because there are errors. 23 assert_equal "can't be blank", recipe.errors.on(:ingredients) 24 end 25 26 def test_should_not_save_unless_instructions_exists 27 recipe = Recipe.new 28 assert !recipe.save # save should fail because there are errors. 29 assert_equal "can't be blank", recipe.errors.on(:instructions) 30 end 31 32 end 33 That might look complicated, but let's break it down. We have four methods there… test_should_create_valid_record, test_should_not_save_unless_title_exists, test_should_not_save_unless_ingredients_exists, and Copyright 2009 Brian P. Hogan 10
  • 18. Validating User Input test_should_not_save_unless_instructions_exists. test_should_create_valid_record simply creates a new instance of Recipe, sets the values for the recipe, and then saves the record. Save should return true, so we use assert to evaluate the value of save. If it evaluates to true, this test passes. If not, it fails. This one needs to pass all the time, as it’s the baseline test. If this test starts failing, that’s an indication that the program’s logic has changed. The other three tests simply attempt to save the record without setting one of the required fields. We expect these to fail because of our validations—in this test we haven’t actually provided any of the required fields, but we are testing for only one error at a time to avoid making our tests too complicated.. We’re also asserting the inverse of true for the save. (assert that Recipe.save is not true. Then we assert that the error messages are set for each field. Each validation has its own message format. In this case, the validates_presence_of validation stores “can’t be blank” in the errors collection, under a key for each invalid attribute. If the title isn’t blank, you’ll find the error message for that in the errors collection, under the :title key. How Tests Work 2.1. How Tests Work Tests actually work by using the test database you defined in database.yml earlier. A test file starts by dumping everything in your database and then updating it so it’s consistent with your development database. Never use the same database for production, development, and tetsting!!!! Each test file is independent of the others. You can feel free to delete as many records as you want in a test and they will be recreated when you start the test again. Each method that starts with ‘test_’ will be run as part of the test suite. 2.2. Fixtures Tests can get data from fixtures. Fixtures are loaded into each test by the fixtures method. You’ll need a fixture for each table in your database, not each model in your system. Modify the fixture for the recipes table by editing /test/fixtures/recipes.yml and add a few recipes. Note Be careful not to use tabs and also be sure to leave a space after each colon! YAML is a tricky little format. 1 ice_water: 2 title: "Ice Cream" 3 ingredients: "3 scoops vanilla ice cream<br>chocolate syrup" 4 instructions: "Scoop ice cream into the bowl and pour chocolate syrup on top." 5 toast: 6 title: "Toast" 7 ingredients: "bread, butter, jelly" 8 instructions: "Place bread in the toaster for 1 minute. Remove from toaster and apply butter to each piece." When the test is run, this data gets loaded into the recipes table and is available within the test. The tests you currently have in your test don’t need these fixtures, but you may write future tests that depend on having data in the test database. For example, you may want to write a test to make sure that there can only be one recipe called “Toast”. That test might look something like this: 1 def test_should_only_have_one_recipe_called_toast Copyright 2009 Brian P. Hogan 11
  • 19. Validating User Input 2 @recipe = Recipe.new(:title =>"Toast") 3 @recipe.valid? 4 Assert @recipe.errors.on(:title).include?("must be unique") 5 end 2.3. Running the Test To run the test, we need to first prepare the test database. We do that by running a rake task. rake db:test:clone This task takes the structures from our development database and creates a new test database that we can use over and over again. Our test is actually a standalone Ruby application. We can run the test directly using Ruby. ruby -Ilib:test testunitrecipe_test.rb1 Everything should work well. You should get no errors or failures. Note You can run all of the unit tests by running rake test:units. This also takes care of initializing the test database for you. 3. Providing Feedback to Users Now that we know our validation works, we should see what it looks like when users attempt to leave fields blank. Active Record’s Validations places error messages in an array which can be accessed by a helper method in a view. The helper method error_messages_for takes in an instance of an Active Record model and attempts to display the error messages in a nice friendly manner. Built in helper methods for text boxes, select boxes, and text areas also are validation-aware. They will become styled automatically, providing additional visual cues. The styles are applied using CSS, so you can modify the way they look. Take a look at Figure 3.1, “User Feedback as provided by Rails validations” [13] to see the results. 1 The -Ilib: argument tells Ruby what folder it should look in to load additional files. Our test case above requires a file called 'test_helper' which is located in the test folder. Copyright 2009 Brian P. Hogan 12
  • 20. Validating User Input Figure 3.1. User Feedback as provided by Rails validations This task alone could take a web developer a few hours to get right. We’ve created a working solution with a unit test in only a few minutes. These validations work for new entries and existing entries. There are numerous plugins available for Rails to change how validation works at the web page level. Most plugins are available at http://www.agilewebdevelopment.com/plugins Copyright 2009 Brian P. Hogan 13
  • 21. Cleaning Up the Scaffolding Chapter 4. Cleaning Up the Scaffolding As stated before, the scaffolding needs some work before it can be used in production. As you become more familiar with the way Rails works, you may find yourself relying less and less on scaffolding to create your pages. 1. Cleaning up the List page The list page is pretty good for starters, but one thing that’s kinda rough about it is that it requires Javascript to be enabled in order to delete records! Yuck!. It might be nice to show just the recipe name and when it was last updated instead of the ingredients and instructions. Remember, the list page is built using whatever fields you specified in your scaffold command. Replace the contents of the page views/recipes/index.erb.html with the following code: 1 <h1>Listing recipes</h1> 2 3 <table> 4 <tr> 5 <th>Title</th> 6 <th>Last Updated</th> 7 <th colspan="2">&nbsp;</th> 8 </tr> 9 10 <% for recipe in @recipes %> 11 <tr> 12 <td><%= link_to h(recipe.title), recipe %></td> 13 <td><%= time_ago_in_words recipe.updated_at %> ago</td> 14 <td><%= link_to 'Edit', edit_recipe_path(recipe) %></td> 15 <td><%= button_to 'Destroy', recipe, :confirm => 'Are you sure?', :method => :delete %></ td> 16 </tr> 17 <% end %> 18 </table> 19 20 <br /> 21 22 <%= link_to 'New recipe', new_recipe_path %> Refresh the index page in your browser. Your new page should resemble something like the one in Figure 4.1, “The modified Index page” [15]. The h() method The h() method sanitizes strings. It will escape any Javascript that someone might have tried to enter. There are other ways to sanitize values entered by your users, but this is the simplest; you just have to remember to use it! Copyright 2009 Brian P. Hogan 14
  • 22. Cleaning Up the Scaffolding Links in Rails Rails makes it easy to link resources. The link_to helper builds links to internal or external resources easily. To create a link to Google, you simple use link_to "Google", "http://www.google.com". We generated our controllers and views using scaffolding so you haven't had much of a chance to see the code yet, but each view is generally associated with a controller action. For example, we can build a link to the "New Recipe" form by creating a link to the "new" action of the "recpies" controller like this: link_to "New Recipe", :controller => "recipes", :action => "new" However, Rails is all about conventions. When we generated the scaffold, the file routes.rb was modified to define a resource. This definition creates some helper methods that make making links incredibly easy. We can create a link to the new recipes page like this: link_to "New recipe", new_recipe_path We can also create a link to the list of recipes like this: link_to "Recipes", recipes_path If we have a recipe object, we can use that recipe object to build a link. link_to recipe.title, recipe_path(recipe) or link_to recipe.title, recipe. URLS for forms use the same convention. It's incredibly handy and one of the nicer features of the framework. Figure 4.1. The modified Index page 1.1. Helpers Rails provides many helper methods to make displaying pages easier. This example shows a few helpers: • link_to : Used to create a hyperlink. We use this because Rails can manage links for us so we don’t need to worry about relative or absolute paths. Rails has a routing system that makes linking things together a snap. • h : This simple helper escapes HTML and Javascript. It helps to sanitize output, in case someone put malicious JavaScript into one of your input fields. Copyright 2009 Brian P. Hogan 15
  • 23. Cleaning Up the Scaffolding • time_ago_in_words : This method takes a time and tells you in words how long ago it was. This is how we get those neat “posted five minutes ago” messages on blogs. The Rails documentation 1 has more information on helpers. Why button_to instead of link_to Notice that the delete feature is a button now instead of links? For safety reasons, we want all links to destructive actions like deletes to be called via post methods. The button_to tag does this for us. We can then style it using CSS so it looks nicer later on. 2. Cleaning up the Show page Take a look at app/controller/recipes_controller.rb and find the show section 1 def show 2 @recipe = Recipe.find(params[:id]) 3 end This code retrieves the recipe from the database. The id sent via the url is sent to the database. This actually generates the sql statement “select * from recipes where id = 1”. The find method is a class method of Recipe and returns an instance of a recipe object. Models in Active Record handle the retrieval and representation of the data. Here we see that it stores the resulting Recipe instance into an instance variable (The @ means instance variable in Ruby.) The instance variable is passed on to the show.html.erb file. Knowing that, we can easily display the information about our recipe. Open app/views/recipe/show.html.erb and replace the contents with 1 <h2><%=h @recipe.title %> [<%= link_to 'Edit', edit_recipe_path(@recipe) %> ]</h2> 2 3 <h3>Ingredients:</h3> 4 <p><%=h @recipe.ingredients %></p> 5 6 <h3>Instructions</h3> 7 <p><%=h @recipe.instructions %></p> 8 9 <%= link_to 'Back', recipes_path %> Your page should look something like Figure 4.2, “The Show Page” [16] Figure 4.2. The Show Page 1 http://api.rubyonrails.com/ Copyright 2009 Brian P. Hogan 16
  • 24. Cleaning Up the Scaffolding 3. Using Partials to share common code The New and Edit forms are virtually identical except for their headings. The actual form could be shared across both files using a partial which is similar to an include file in PHP.. This way, if you add a field to the form, you only need to add it to one file instead of two. Create a new file in app/views/recipes called _form.html.erb. The filename should begin with an under- score because that’s how Rails distinguishes partials from regular views. Open up the new.html.erb file and find this code: 1 <p> 2 <%= f.label :title %><br /> 3 <%= f.text_field :title %> 4 </p> 5 <p> 6 <%= f.label :ingredients %><br /> 7 <%= f.text_area :ingredients %> 8 </p> 9 <p> 10 <%= f.label :instructions %><br /> 11 <%= f.text_area :instructions %> 12 </p> Copy that code to your clipboard and paste it into _form.html.erb. Once it's pasted, remove the code from the new.html.erb file.. Open edit.html.erb and locate the same code. Remove it from the file. Now add this line to edit.html.erb, in place of the code you just removed: 1 <%= render :partial =>"form", :locals=>{:f => f} %> The :locals => {:f => f} option allows you to pass variables into the partial. Since the variable f for the form is a local variable, it needs to be passed to the partial so the partial can “see” it and access it. The edit.html.erb file should now look like this: 1 <h1>Editing recipe</h1> 2 3 <%= error_messages_for :recipe %> 4 5 <% form_for(@recipe) do |f| %> 6 7 <%= render :partial =>"form", :locals=>{:f => f} %> 8 9 <p> 10 <%= f.submit "Update" %> 11 </p> 12 <% end %> 13 14 <%= link_to 'Show', @recipe %> | 15 <%= link_to 'Back', recipes_path %> Add the same line of code to new.html.erb. in place of the code you previously removed. You’re now sharing code between two views using a partial. 4. Where’s the rest of my HTML? You’ve probably noticed that our view pages have not included any required HTML elements, nor have they mentioned anything about a style sheet. Yet we can see styles being rendered and we see a lot of HTML markup if we view the source. Where’s this coming from? Copyright 2009 Brian P. Hogan 17
  • 25. Cleaning Up the Scaffolding Rails has a wonderfully complex yet simple template mechanism. Look in the app/vies/layout folder and you’ll see a file called recipes.html.erb. This file was created during your scaffold operation and is automatically linked to the recipes controller. This file wraps any view files you render from within the recipes controller. If you want one single layout for your entire application, you can rename this file to application.html.erb and every controller will use it. This file can use any instance variables (those ones prefixed with @) set in the controller, including variables created within the view files themselves, because it is read last before being sent to the browser. This means you can set the page title in the individual controller actions or even in the .erb files themselves. Copyright 2009 Brian P. Hogan 18
  • 26. Adding Categories Chapter 5. Adding Categories A recipe should be able to be categorized. For this example, we’ll just say that a recipe can only belong to one category, and a category can have many recipes. We’ll say it that way because that’s how Active Record allows us to express relationships. 1. Create a category model and table We don’t need to create a full interface to manage categories at this time, so create the new model by dropping to a command prompt and typing ruby script/generate model Category name:string Run the newly-created migration by executing the command rake db:migrate from the command line. It will create the new table. 2. Adding some default records with Rake Sometimes it’s nice to have your database pre-populated with records. You saw how fixtures can do that with test data, but that’s not always a good choice. Migrations could be used to insert data into your database but that can be volatile as well. The best approach is to use rake, which is the same tool you’ve been using to run your migrations. Rake is an automation language. To use it, you simply create a file with some tasks and then execute it via the rake command. Rails projects look for Rake tasks in files with the .rake extension in the project’s lib/tasks folder. Create a new file in that folder called import.rake. Place this code in the file: 1 namespace :db do 2 3 desc "Puts default categories in the database" 4 task :import_categories => :environment do 5 6 Category.create :name =>"Beverages" 7 Category.create :name =>"Deserts" 8 Category.create :name =>"Appetizers" 9 Category.create :name =>"Entrees" 10 Category.create :name =>"Breakfast" 11 Category.create :name =>"Sandwiches" 12 13 end 14 end A namespace is just a container for code like in any other language. When you issued the command rake db:migrate you called the migrate task within the db namespace. We’ll follow that same convention here. To import the records into your database ,issue the command rake db:import_categories 3. Modifying the Recipes table Since we want to have a relationship between categories and recipes, we have to place a foreign key in the recipes table so it can be associated with a recipe. We’ll do this with a migration too. Copyright 2009 Brian P. Hogan 19
  • 27. Adding Categories Create a new migration. From the command line, execute the command ruby script/generate migration add_category_id_to_recipes This will create a new migration file db/migrate/XXXXXXX_add_category_id_to_recipes.rb. Open the file and replace it with the following code: 1 class RecipeCategory < ActiveRecord::Migration 2 def self.up 3 add_column :recipes, :category_id, :integer 4 end 5 6 def self.down 7 remove_column :recipes, :category_id 8 end 9 end Run the migration to alter the database. (rake db:migrate). At this point you will need to stop and restart your web server. This is only necessary with SQLite3, and only because you changed a table's structure.. Other databases can be modified without restarting the web server. Press CTRL+BREAK to stop Mongrel and then restart it by executing the command ruby script/server 4. Creating an Association Between a Recipe and a Category Associations allow objects to interact. Associations are methods that map the primary keys of one table to the foreign keys of another; the relational mapping part of “object-relational mapping”. Open app/models/recipe.rb and modify its contents with the following code: 1 class Recipe &lt; ActiveRecord::Base 2 belongs_to :category 3 validates_presence_of :title, :ingredients, :instructions 4 end 5 The belongs_to class method takes in a symbol name of a class with which we wish to associate. Rails needs no further information because it will assume that :category references a class called Category, that the table name will be categories, and that this table (recipes) has a foreign key column called category_id that will reference the id column in the categories table. Of course, we can override these assumptions, but it’s easier just to follow convention. This association adds some new methods to an instance of Recipe. We can now access the name of the category directly through the recipe. recipe = Recipe.find(1) # gets recipe with id of 1 recipe.category.name # gets the associated category name 4.1. Lazy vs. Eager Loading The above code will do the retrieval using lazy loading, meaning that two SQL statements will be called. This could be bad if we were retrieving all recipes and displaying the category for each one. If you have 200 recipes, the above code would generate 201 SQL statements! Copyright 2009 Brian P. Hogan 20
  • 28. Adding Categories Thankfully there is a solution for situations like this… eager loading. Rails will generate proper left joins for us if we specify the objects to include. recipe = Recipe.find(1) becomes recipe = Recipe.find(1, :include => [:category]) and now only one statement is sent to the database. 5. Adding categories to the controllers and views In order to add the category selection to the forms and views, we need to do some work in the controller. 5.1. The New and Edit forms Open app/controller/recipes_controller.rb and locate the new method. Modify it so it retrieves the categories into an instance variable called @categories. Remember that a controller’s instance variables are then accessible in the view pages. 1 def new 2 @categories = Category.all 3 @recipe = Recipe.new 4 respond_to do |format| 5 format.html # new.html.erb 6 format.xml { render :xml => @recipe } 7 end 8 end Now find the edit method and modify it so it also retrieves the categories into @categories. 1 def edit 2 @categories = Category.all 3 @recipe = Recipe.find(params[:id]) 4 end Open app/views/recipes/_form.html.erb and add the following block at the end of the file: 1 <p> 2 <%= f.label :category_id %><br /> 3 <%= f.select :category_id, @categories.collect{|c| [c.name, c.id] }, :include_blank => true %> 4 </p> This code adds a select box which will contain all of the categories so that your users can place a recipe into the category chosen by the dropdown. This is an example of the select helper. The collect method iterates through all the categories and returns an array. In this case we’re returning an array of arrays which the select helper can use to build the form. This is an example of a block and you’ll see lots of these in Rails applications and Ruby code. We’re also including a blank option so that a user doesn’t have a category already selected when they view the page. Copyright 2009 Brian P. Hogan 21
  • 29. Adding Categories 5.2. The Show view When we display a recipe, we want to now show the category for the recipe. We can do that easily thanks to the way the belongs_to association works. When we associated a category to a recipe using that association, it added a method to our Recipe model called category, which returns an instance of the associated category record. Locate the show action in recipes_controller and add eager loading for the category using the :include option for find. 1 def show 2 @recipe = Recipe.find(params[:id], :include=>[:category]) 3 respond_to do |format| 4 format.html # show.html.erb 5 format.xml { render :xml => @recipe } 6 end 7 end Open app/views/recipes/show.html.erb and add <p>Category: <%= h(@recipe.category.name) rescue “No category found” %></p> somewhere on the page. When you refresh, you'll see the category displayed. Tip The rescue statement catches a possible exception that could be thrown if the recipe does not yet have an assigned category. Your recipes don't all have the category assigned yet, and without this rescue statement, this page would fail to render. 5.3. The List view Find the index action in recipes_controller.rb and add the :include option to the find to eager-load the category information just like the previous example. 1 def index 2 @recipes = Recipe.all :include => [:category] 3 respond_to do |format| 4 format.html # index.html.erb 5 format.xml { render :xml => @recipes } 6 end 7 8 end Open app/views/recipes/index.html.erb and modify it so you can see the category name in the table. You’ll need to add a column heading as well as the data cell itself. Remember to use the association to retrieve the category name just like you did on the show page! 6. Test it out With the associations in place and the views fixed up, go ahead and play with your application. Notice how you can now add categories to your recipes, and when you edit an existing recipe, its associated category automatically shows up in the dropdown list. Copyright 2009 Brian P. Hogan 22
  • 30. Other Rails Tidbits Chapter 6. Other Rails Tidbits There's a lot more to the Rails framework than what we covered here. Let's explore a few other features. 1. Writing Documentation with RDoc Documenting code is one of the most useful things a developer can do. Unfortunately it’s often done poorly if it’s even done at all. Ruby on Rails aims to change how developers write documentation by making use of RDoc. RDoc is a program that can parse Ruby files for comments and convert these comments to HTML pages or other formats. It generates very clean and nice-looking documentation and is so easy to use that developers quickly come to actually enjoying documentation. Any comments located directly above a class or method declaration will be interpreted by the RDOC parser to be the comments for that given block of code. Here’s an example of some commented code. 1 #=Recipes 2 # Recipes are added, removed, maintained, and viewed using 3 # the actions in this controller. 4 #==Authentication 5 # There is no authentication on this controller 6 class RecipesController < ApplicationController 7 8 # This action handles the default document (Index) and 9 # simply redirects users to the list action. 10 def index 11 list 12 render :action => 'list' 13 end 14 15 end When we run the command rake doc:app, our HTML documentation will be created for us. See Figure 6.1, “RDoc output in HTML” [23] Figure 6.1. RDoc output in HTML Copyright 2009 Brian P. Hogan 23
  • 31. Other Rails Tidbits 2. Annotating Models One of the things that can get confusing with Rails is the fact that the models don’t have much code. Because the methods are generated for you, you can’t look at a model and tell what database fields you refer to unless you were to comment them yourself. Thankfully we can handle this simply by installing a plugin called annotate_models written by the creator of RDoc, Dave Thomas. Install the plugin by executing this command from the command line ruby script/plugin install http://repo.pragprog.com/svn/Public/plug- ins/annotate_models Note You’ll need to have the Subversion client tools installed on your machine for this to work and the svn command needs to be on your path. Visit http://subversion.tigris.org/servlets/Pro- jectDocumentList?folderID=91 to get the latest version if you don't have it.. After installation, be sure to close any open command prompt windows. Then re-open your command prompt window and navigate back to the root of your project.) Once installed, run the command rake annotate_models Your models will now be commented with the schema definition. This will then be placed in your documentation the next time you generate your docs. You can see the output in Figure 6.2, “Annotations added to a model” [24] Figure 6.2. Annotations added to a model 1 2 # == Schema Information 3 # Schema version: 20090419074728 4 # 5 # Table name: recipes 6 # 7 # id :integer not null, primary key 8 # title :string(255) 9 # ingredients :text 10 # instructions :text 11 # created_at :datetime 12 # updated_at :datetime 13 # category_id :integer 14 # 15 16 class Recipe < ActiveRecord::Base 17 belongs_to :category 18 validates_presence_of :title, :ingredients, :instructions 19 end 20 21 22 3. Debugging and Exploring with Console One of the ways you can debug a Rails application is with unit tests. However, often times you might not know what to write. That’s where console comes in. Console lets you load the entire Rails application into the Interactive Ruby environment so you can execute commands and interact with your application. Copyright 2009 Brian P. Hogan 24
  • 32. Other Rails Tidbits From the root of your project, execute the command ruby script/console to enter the console. Once the console is loaded, you can start experimenting with your objects, as shown in Figure 6.3, “Using the Rails Console to work with objects” [25] Figure 6.3. Using the Rails Console to work with objects Loading development environment (Rails 2.3.2) >> recipe = Recipe.create :title => "test", :ingredients => "stuff", :instructions => "mix together" => #<Recipe id: 2, title: "test", ingredients: "stuff", instructions: "mix together", created_at: "2009-04-19 08:21:03", updated_at: "2009-04-19 08:21:03", category_id: nil> >> id = recipe.id => 2 >> recipe.category => nil >> category = Category.find_by_name "Sandwiches" => #<Category id: 6, name: "Sandwiches", created_at: "2009-04-19 07:50:00", updated_at: "2009-04-19 07:50:00"> >> recipe.category = category >> recipe.changed => ["category_id"] >> recipe.save => true >> exit In the above example, I use the console to create a new recipe and save it to the database. I then retrieve the id for the recipe. Then I use the find method on Recipe to locate the recipe again. Then I see if it has a category. Of course, it doesn’t so I fetch a category from the database and assign it to my instance. I use the changed method to see what columns in the database have changed. The association is not saved until I execute the save method of my instance. This is just the beginning, but it shows how you can use the console to learn more about how the methods on the classes work without having to write any view pages or controller code. 4. Logging Rails applications automatically log requests and responses to the various logs. One log you should really keep an eye on is your development.log file. It contains a lot of useful information such as the parameters sent on each request as well as the SQL statements created by Rails and sent to the database. This is the place you’ll want to look to tune your application. Not only can you see if you’re executing too many SQL statements for the job at hand, but you can also see how long it took Rails to serve the request to your client. 5. Writing your own SQL statements At first glance, Rails may seem limited. We’ve gone through this entire project without writing any SQL. A lot of the time we won’t have to worry about it. However, it is still very possible for us to get into the code and do what we need to do. For example, one of the methods in Active Record is called find_by_sql which allows us to look records up using our own custom SQL statement. @results = Recipe.find_by_sql "select r.title, c.name from recipes r Copyright 2009 Brian P. Hogan 25
  • 33. Other Rails Tidbits join categories c on r.category_id = c.id" => [#<Recipe:0x3750478 @attributes={"name"=>"Beverages", "title"=>"Test"}>] You have to understand Ruby to understand what this example returns, so I’ll help out. The square brackets ([]) sur- rounding the result means that you're dealing with an Array. The #<Recipe piece means it’s a Recipe object. So when you use the find_by_sql method, you receive an array of objects which you can then iterate over. @results.each do |recipe| puts recipe.name # print to STDOUT puts recipe.title # print to STDOUT end Note that a new method title has been created in the instance of the class. Active Record inspected the column names that came back from the database and dynamically created accessor methods for us to use. Warning Never use “puts” in your Rails application directly. It can cause problems that you may not find later on. It’s only to be used in tests and in the console to help you debug. If you’re wondering, it’s equivalent to system.out.println or echo. There are many other features in Rails that make it extremely flexible. Don’t get fooled by the hype about ORM and scaffolding. Rails is much more than that! Copyright 2009 Brian P. Hogan 26
  • 34. Development and Deployment Chapter 7. Development and Deployment 1. Exploring Development Tools There are several different tools you can use to easily build Rails applications. • If you’re on a Mac, you have to check out TextMate. While not an IDE, it is built with Rails development in mind and is just a dream to work with when you see it. It’s the featured editor in all of the Rails screencasts. See http:// macromates.com/ for more information. • Those interested in a full-blown IDE for Rails development will love NetBeans Ruby IDE from Sun (yup, the Java guys). Snag your copy at http://download.netbeans.org/netbeans/6.0/final/ and be sure to grab the one for Ruby. You will need the Java SDK as well to run this, but it’s worth it. • Windows users absolutely need to look at Ruby In Steel. There's a free version available at http:// www.sapphiresteel.com/Ruby-In-Steel-New-Free-Edition that actually includes pretty much everything you need to get started with Rails. • Advanced users will definitely want to look at vim with the rails.vim plugin. Rails.vim plugin: http://www.vim.org/scripts/script.php?script_id=1567 2. Deploying Rails Applications Deploying Rails applications is no trivial task. Rails applications require more setup work than PHP applications and there are lots of things that can go wrong when you’re first starting out. Do not attempt deployment until you are very comfortable with the Rails framework. Applications can be deployed using a variety of methods, but the most popular method is to use Passenger. Passenger works with Apache or Nginx to make deploying Rails applications extremely easy. The Passenger site1 provides more information on deploying applications using this method. Another excellent method for deployment is Apache or Ng- inx balancing a collection of Mongrel server instances, however this method is expected to be abandoned in favor of Passenger. There are many web hosting companies that support Rails Shared hosts such as Dreamhost, RailsPlayground, and Blue- host keep the cost low by sharing space and memory with other users. This is a great low-cost way to launch your application. If you need high availability, you can look at RailsMachine and EngineYard, two solutions that promise to host large Rails sites with ease. They are significantly more expensive than shared hosting plans. EngineYard is incredible, but you can’t afford it unless you are really making money. It’s worth every penny though and they do offer a Solo plan using Amazon's EC2 cloud. If you just want to set things up yourself on dedicated virtual servers, you could look at Slicehost, Linode [http:// www.linode.com/], and Rimuhosting [http://www.rimuhosting.com/]. Rimuhosting provides good support for Rails on their virtual servers, as does Linode. Deploying applications is not trivial, but it's not a terrible experience either. Once you've gotten your head around how it all works, you'll have no problem moving apps around. 1 http://www.modrails.com/ Copyright 2009 Brian P. Hogan 27
  • 35. Development and Deployment More information on deployment can be found in the book Deploying Rails Applications from the Pragmatic Bookshelf, including a section on deploying on Windows, written by your humble author. Copyright 2009 Brian P. Hogan 28
  • 36. Homework and Exploration Chapter 8. Homework and Exploration If you want to take the exercise further, you can try some of the ideas below. The answers are not provided but the solutions for each problem can be found by looking at similar exercises in the preceding tutorial. 1. Document some other methods in your controllers and models and then regenerate the docs. Here are some simple formatting symbols: • # is the comment • = is a large header • == is a level 2 header • --- is a horizontal rule • * is a bullet 2. Create a has_many association from Category to :recipes • Write a unit test that tests this relationship. (You’ll need to make fixtures for categories and recipes and you’ll need to load both of these in the test file.) • See http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html for details on has_many 3. Create a controller and views to manage the categories. Use the recipe controller and views as an example. If you choose to scaffold this, you may need to undo some work you’ve done so be careful. It’s easier to write it by hand. • When you display a category, display the recipes associated with that category, making use of the has_many association you created. • On the Show page for a recipe, make a link to the category <%=link_to @recpie.category, show_category(@recipe.category) %> 4. Extra Credit: When a category is deleted, set all associated recipes to a nil category using a before_destroy ActiveRe- cord callback. Copyright 2009 Brian P. Hogan 29
  • 37. Where To Go Next? Chapter 9. Where To Go Next? Hopefully this exercise gave you enough of an overview of the Ruby on Rails framework to see the potential impact it has on rapid application development. From here, you should be able to extend this assignment by doing the homework or explore further by coming up with your own application, using this as a model. 1. Books • Learn to Program (Chris Pine) http://www.pragprog.com/titles/fr_ltp/learn-to-program • Agile Web Development with Rails (Dave Thomas) http://www.pragprog.com/titles/rails3/agile-web-development-with-rails-third-edition • Ruby for Rails (David A. Black) http://www.manning.com/black/ • Programming Ruby (Dave Thomas) http://www.pragprog.com/titles/ruby/programming-ruby or older version online for free at http:// www.rubycentral.com/book/ • Deploying Rails Applications (Ezra Zygmuntowicz, Bruce Tate, Clinton Begin, Geoffrey Grosenbach, and Brian Hogan) http://www.pragprog.com/titles/fr_deploy/deploying-rails-applications • Rails for .Net Developers (Jeff Cohen and Brian Eng) http://www.pragprog.com/titles/cerailn/rails-for-net-developers • Rails for Java Developers (Stuart Halloway and Justin Gehtland) http://www.pragprog.com/titles/fr_r4j/rails-for-java-developers • Rails for PHP Developers (by Derek DeVries and Mike Naberezny) http://www.pragprog.com/titles/ndphpr/rails-for-php-developers • The Rails Way (Obie Fernandez) http://www.amazon.com/Rails-Way-Addison-Wesley-Professional-Ruby/dp/0321445619 2. Online Resources • Ruby on Rails Discussion group (http://groups.google.com/group/rubyonrails-talk) • #rubyonrails IRC channel (http://wiki.rubyonrails.org/rails/pages/IRC) • Peepcode (http://peepcode.com/) • Railscasts (http://railscasts.com/) Copyright 2009 Brian P. Hogan 30
  • 38. Where To Go Next? • Railsforum (http://www.railsforum.com/) Copyright 2009 Brian P. Hogan 31
  • 39. Index database reflection, 8 Index dynamic method creation, 9 , 15 P Partials, 2 A sharing code with, 17 accessor, 9 Array, 26 R Associations rake belongs_to, 20 loading data with, 19 eager loading, 20 Rake tasks Cloning the test database from the development database, 12 C RDoc, 23 example, 23 Console Generating documentation, 23 debugging, 25 Refactoring, 2 Controllers, 1 Rubygems Gems, 3 D data populating database with seed data, 19 S Scaffolding, 6 database.yml, 4 issues with, 7 Deploying, 27 script/server, 8 development environments, 27 SQL Documentation statements in the Rails logs, 25 Annotating Models with schema info, 24 writing your own, 25 generating documentation with RDOC, 23 SQLite3 automatic creation, 5 E installation of, 5 Exception Handling Symbols, 9 rescue, 22 T F Test-driven development Fixtures, 11 TDD, 2 Tests G running a single test, 12 Generators, 6 running all unit tests, 12 scaffold, 6 U H Unit Tests, 10, 11 Helper methods running, 12 link_to, 15 Helpers, 2 V Validations, 9 L validates_presence_of, 9 Layouts, 2 Views, 1 Links, 15 displaying errors, 12 logging, 25 master layout, 17 M Migrations, 7 running, 8 Model-View-Controller pattern, 1 Models, 1 Copyright 2009 Brian P. Hogan 32