Oomoo

March 11, 2008

A Model Model

Filed under: model, rails — oomoo @ 1:38 pm

Example and details about a Rails Model:

*This beginning description was transcribed from a training video for which I am looking for the source to give credit. 

A “Model” is a Class that deals with the manipulation of data.  Classes allow the combination of data and methods in one place.  Because it is a full-blown Class, it can have any number of its own variables and methods.  The Model class is the perfect place for data validation for a Rails system.  It actually makes more sense to store data-based logic here than in the database (assuming that other systems are not monkeying with your data).  This is one of the reasons most Rails programmers don’t use database constraints (one of the big reasons is ActiveRecord doesn’t like it either). 

Generally, a Model Class is comprised of several things:

  • Associations  (Relationships to other tables in the database)
  • Validations  (special rails “validates…” statements)
  • Accessors  (creates “getter” and “setter” methods automatically)  (methods used to get/put data in a private class variable)
  • CallBacks  (hooks into the underlying rails logic that allow you to inject your code a specific steps)
  • Class Variables (@@varname, only one set maintained across all objects of the class)
  • Instance Variables (@varname, each object has its own set to manipulate at will)
  • Class Methods (generic logic methods not tied to specific data) (or operate on the class itself, like instance counters)
  • Instance Methods (any method that is not a class method)

# Associations ================================================

  has_one :o rder_account_type

  has_many :o rders

  belongs_to :o rder_address

  belongs_to :o rder_user

  belongs_to :o rder 
 

# Validations =======================================================

  validates_presence_of :o rder_user_id, :o rder_address_id, :o rder_id

  validates_length_of :cc_number, :maximum => 20

  validates_format_of :cc_number, :with => /^[\d]*$/,

                      :message => ERROR_NUMBER

  validates_format_of :credit_ccv, :with => /^[\d]*$/,

                      :message => ERROR_NUMBER

  validates_numericality_of :expiration_month, :expiration_year 
 

# Accessors =======================================================

  attr_accessor :name, :promotion_code, cc_number 
 

# CALLBACKS =================================================================

  before_save :set_product_cost

  before_destroy{|record | Person.destroy_all “firm_id=#{record.id}”} 

  During the life cycle of an active record object, you can hook into 8 events:

      (-) save

      (-) valid?

      (1) before_validation

      (2) before_validation_on_create

      (-) validate

      (-) validate_on_create

      (3) after_validation

      (4) after_validation_on_create

      (5) before_save

      (6) before_create

      (-) create

      (7) after_create

      (8) after_save  
 

# CLASS VARIABLES =======================================================

  @@number_of_instances

  @@version 
 

# INSTANCE VARIABLES =======================================================

  @total_line_items

  @time_created 
 

# CLASS METHODS =============================================================

  # List of years for dropdown in UI

  def self.years

    start_year = Date.today.year

    years = Array.new

            10.times do

      years << start_year

      start_year += 1

    end

    return years

  end 

  # Search by order_number

  def self.search(search_term, count=false, limit_sql=nil)

    if (count == true) then

      sql = “SELECT COUNT(*) “

    else

      sql = “SELECT DISTINCT orders.* “

      end 

      sql << “FROM orders “

      sql << “WHERE orders.order_number = ? “

      sql << “ORDER BY orders.created_on DESC “

      sql << “LIMIT #{limit_sql}” if limit_sql 

      arg_arr = [sql, search_term, "%#{search_term}%"] 

      if (count == true) then

        count_by_sql(arg_arr)

      else

        find_by_sql(arg_arr)

      end

  end

   
 

# INSTANCE METHODS ==========================================================

  def status

    code = OrderStatusCode.find(:first, :conditions => ["id = ?", self.order_status_code_id])

    code.name

  end 

  def tax_cost

    (self.line_items_total) * (self.tax/100)

  end 

  def name

    return “#{billing_address.first_name} #{billing_address.last_name}”

  end 
 
 
 
Create A Model 

ruby script/generate model MyTable  (from Ruby command line… in your App’s folder) 

creates…

   db/migrate/000_create_mytable.rb

   app/models/mytable.rb

   test/unit/mytable_test.rb

   test/fixtures/mytable.yml 

Edit The Model 

edit…  db/migrate/000_create_mytable.rb 

“RAKE” your changes 

rake db:migrate   (from Ruby command prompt,  in your App’s folder) 

Test

ruby script/console   (from Ruby command prompt,  in your App’s folder)

     r = MyTable.new

     r.myfield = ‘new value’

     r.save

Migration-Related Rake Commands

Filed under: migration, rails, rake — oomoo @ 1:28 pm

Here are some of the Rake commands that are used when doing migrations (and some tips)…

rake db:migrate   Migrate the database through scripts in db/migrate. Target specific version with VERSION=x  

rake db:schema:dump  Dump the database structure into the “master migration script” db/schema.rb

rake db:structure:dump  Dump the database structure to a SQL file  

rake db:schema:load  Load a schema.rb file into the database

rake db:fixtures:load  Load fixtures into the current environment’s database. Load specific fixtures using FIXTURES=x,y  

rake db:sessions:clear  Clear the sessions table

rake db:sessions:create Creates a sessions table for use with CGI::Session::ActiveRecordStore  

rake db:test:clone   Recreate the test database from the current environment’s database schema

rake db:test:clone_structure  Recreate the test databases from the development structure

rake db:test:prepare   Prepare the test database and load the schema

rake db:test:purge   Empty the test database  
 

Next “Migration Number” that needs to be applied, is stored in table “schema_info” field named “version” 
 
 
 

Test the Migration Scrips…   “rake db:migrate –dry-run –trace” 
 

Apply the Migration Scripts…  “rake db:migrate”

    Did an error occur?  See the “troubleshooting” section below. 
     

Roll back a script…  “rake db:migrate VERSION=004″    (substitute the desired “version #” for the number “4″) (Use the number “0″ to drop the tables) 

    If you manually “dropped” the table yourself, you need to add the table back (just add one field), so the rollback will work.
    OR, you could manually change the number stored in “schema_info.version” to a number prior to when the table existed. 
    It is a good idea to “roll back” EVERY script, just to make sure your “self.down” works properly (before the next \db\migrate\ script gets created). 

Apply the Migration Script…Again  “rake db:migrate”   (After it rolls back successfully, just “rake db:migrate” again to put your migration back into effect.) 

Regenerate the “schema.rb” file to include your new model…  “rake db:schema:dump” 

Manually Testing A Model/Controller

Filed under: MVC, controller, model, rails — oomoo @ 1:26 pm

One of the cool things about Rails, is that with almost no work, you can easily test your new Model/Controller combination.

*Newbie Notes

To initially test a new model-controller, put the line:  “scaffold :mymodelname“  in the controller class code (comment out any other existing code).

This allows you to test that everything is hooked up properly using full CRUD scaffolding.

(No new files are created and no coding changes are done, the scaffold is generated on-the-fly). 
 

Start InstantRails (if you are using it)

   …OR…

      Start Apache/IIS

      Start MySQL 

Start the Ruby Server

    start a “ruby console” command line session
    cd myappname
    ruby script/server
    You will see…
    => Booting Mongrel (use ’script/server webrick’ to force WEBrick)
    ** Starting Rails with development environment… 
     

Browse the View

      http://localhost:3000/myviewname    (ex:  http://localhost:3000/order) 
 

Experiment with the Model

    Start a Ruby Console:
          cmd…  ruby script/console 
    Create a Record
          @myorder = Order.new 
          myorder.quantity = 5
          myorder.price = 5.95
          myorder.desc = ‘Just a test’
          myorder.ordtime = Time.now 
    Save a Record
          @myorder.save 
    Find a Record
          myorder = Order.find :first 
    Delete a record
          myorder.destroy 
     
     

Troubleshooting 

- ActiveRecord::StatementInvalid: Mysql::Error: Column cannot be null: INSERT INTO

    - You have fields in your table that do not allow NULL.  You will need to supply a value for them before you can save.  *scaffold handles all of this for you. 

- Internet Explorer cannot display the webpage

  • You do not have Apache/IIS started.
  • You do not have MySQL started.
  • You do not have the Ruby server started  (See “Start the Server” above). 
    Remember, your “view” webpage is trying to execute ruby scripts that reside back on the server.  Without a server component running, it cannot do anything.
  • You did not enter the address correctly in the browser (mispelled the view name).

Create A New Model/Controller

Filed under: MVC, controller, model, rails — oomoo @ 1:23 pm
These instructions use an example database table named… orders 
Model
    “ruby script/generate model order”     (Note – use the singular name “order”, not “orders”) 
    “ruby script/generate scaffold order”   (This will create BOTH the Model and Controller and will implement the basic Scaffold functionality as your base code) 
    This command also creates the following files:
             app/models/ order.rb
             test/unit/ order_test.rb
             test/fixtures/ orders.yml 

Controller

    “ruby script/generate controller order index”         (Note – use the singular name “order”, not “orders”) 
    creates…
      app/contollers/orders_controller.rb
      app/helpers/orders_controller.rb
      app/views/orders/index.rhtml
      test/functional/orders_controller_test.rb 
     

View

    Automatically created in the Controller step above. 
    To manually create
          create a folder:  app/views/orders/
          create a file:  index.rhtml  (in the new folder) 
     

Test It

  ruby script/server  (Note – Ruby command line, from the “application” folder) 

  http://localhost:3000/orders (Note – “orders” is the name of the “view folder”.  This will display the “index.rhtml” file by default)

Create A New Migration Script

Filed under: migration, model, rails — oomoo @ 1:19 pm

Overview:

  1. Generate the script
  2. Edit the script
  3. Test the Script
  4. Apply the Script
  5. Roll back a script
  6. Apply the Script… again
  7. Check the “schema.rb” that gets generated
    NewbieNote*  The Database.YML file dictates the database upon which your code (and rake commands) operate.  For example, this snippet from a database.yml file will execute all commands/code on the “mybd_development” database. 
    development:
      adapter: mysql
      database: mydb_development
      username: root
      password:
      host: localhost 
     

Details:

Generate the scripts…

    For a new Table/Model…      ”ruby script/generate model order”
          This command also creates the following files:
             app/models/ order.rb
             test/unit/ order_test.rb
             test/fixtures/ orders.yml 
    For a new Table/Model (just the migration script)…   ”ruby script/generate migration create_orders_table”
    For making modifications…      ”ruby script/generate migration this_is_the_name_of_my_migration”
    For existing Tables (legacy data)…      …see the related topic ‘Create Migration For Existing Tables’ 
     
    (you should use explicit names, describing what the migration will do, since the generator will create a file with this same name and overwrite any previously existing one) 
    Scripts are Stored In:  \db\migrate\ 
    Scripts are Sequentially Numbered…  001_create_orders_table.rb, 002_create_second_table.rb, etc. 
    Next Number that needs to be applied, stored in table “schema_info” field named “version” 
    “db:migrate” will apply the scripts in sequential order, starting with the next number after the one stored in “schema_info.version”. 
     

Edit the script file (see below) 

    You probably want to include the “:force => true” parameter when creating a new table. 
    Make sure you have properly coded the “self.down” method in case you need to roll back to a prior version! 

Test the Migration Scrips…   “rake db:migrate –dry-run –trace” 

    If “nothing” happens, then your migration was not applied.  The most obvious reason is that the “schema_info.version” field already
    contains a number equal to, or higher than, the migration you are trying to apply. 
     

Apply the Migration Scripts…  “rake db:migrate”

    Did an error occur?  See the “troubleshooting” section below. 
    If “nothing” happens, then your migration was not applied.  The most obvious reason is that the “schema_info.version” field already
    contains a number equal to, or higher than, the migration you are trying to apply. 
     

Roll back a script…  “rake db:migrate VERSION=004″    (substitute the desired “version #” for the number “4″) (Use the number “0″ to drop the tables) 

    If you manually “dropped” the table yourself, you need to add the table back (just add one field), so the rollback will work.
    OR, you could manually change the number stored in “schema_info.version” to a number prior to when the table existed. 
    It is a good idea to “roll back” EVERY script, just to make sure your “self.down” works properly (before the next \db\migrate\ script gets created). 

Apply the Migration Script…Again  “rake db:migrate”   (After it rolls back successfully, just “rake db:migrate” again to put your migration back into effect.) 

Check the “schema.rb” file to check your new model.  Can be run manually by…  “rake db:schema:dump” 

_______________________________________________________________________________________________

_______________________________________________________________________________________________ 
 
 

Table/Model Naming Conventions: 

    Model / Class – ( singular, first letter Capitalized, CamelCase for models like SteeringWheel)
    Table / schema (in database) – ( plural, with underscores instead of spaces between words, like steering_wheels)  
    Model/Class       Table/Schema
    Order                 orders
    LineItem             line_items
    Person                people
    Address             addresses
    Legacy               legacies
    Mouse               mice 
     

__________________________________________________________________________________________________

__________________________________________________________________________________________________ 
 

Migration Data Types

      string

      text

      integer

      float

      float :limit => 25   (yields a double)

      date

      time

      datetime

      timestamp

      binary

      boolean

      decimal, :precision => 15, :scale => 10   
               (precision = total digits, scale = digits right of decimal point)
 

      t.column :, :string, :limit => 0, :default => , :null => false

      t.column :, :integer, :default => ‘0′ :null => false

      t.column :, :decimal, :precision => 10, :scale => 0 :default => ‘0′ :null => false

      t.column :, :date, :default => ‘0000-00-00′, :null => false 
 

      *Force the ordCustPK field to be a Foreign Key (FK) referencing Customers.CustPK:

      t.column :o rdCustPK, :integer, :default => ‘0′ :null => false,  
               :references
=> [:customers, :CustPK] 

      *Force the Primary Key (PK) of the customers table to be the CustPK field:

      create_table(:customers, :force => true :primary_key => ‘CustPK’) 
 

______________________________________________________________________________________________

______________________________________________________________________________________________ 
 

Some Additional Migration Syntax

      add_index “activitylog”, ["logcreatedate"], :name => “logcreatedate”

      add_constraint :projects, :unique => :name

      add_constraint :projects, :foreign_key => :o wner_id, :references => :users

            OR… execute ALTER TABLE posts ADD CONSTRAINT fk_posts FOREIGN KEY(discussion_id) REFERENCES discussions(id) 

      say_with_time “Updating salaries…”

            …Inserts your own messages/benchmarks by using the #say_with_time method 
 

Available transformations

  • create_table(name, options) Creates a table called name and makes the table object available to a block that can then add columns to it, following the same format as add_column. See example above. The options hash is for fragments like “DEFAULT CHARSET=UTF-8″ that are appended to the create table definition.
  • drop_table(name): Drops the table called name.
  • rename_table(old_name, new_name): Renames the table called old_name to new_name.
  • add_column(table_name, column_name, type, options): Adds a new column to the table called table_name named column_name specified to be one of the following types: :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean. A default value can be specified by passing an options hash like { :default => 11 }. Other options include :limit and :null (e.g. { :limit => 50, :null => false }) — see ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
  • rename_column(table_name, column_name, new_column_name): Renames a column but keeps the type and content.
  • change_column(table_name, column_name, type, options): Changes the column to a different type using the same parameters as add_column.
  • remove_column(table_name, column_name): Removes the column named column_name from the table called table_name.
  • add_index(table_name, column_names, index_type, index_name): Add a new index with the name of the column, or index_name (if specified) on the column(s). Specify an optional index_type (e.g. UNIQUE).
  • remove_index(table_name, index_name): Remove the index specified by index_name.

____________________________________________________________________________________________________

____________________________________________________________________________________________________ 
 

Primary Key:

The Rails convention is for every table to have a field named “id” which is an auto-incrementing integer primary key.  
 
 
 

_____________________________________________________________________________________________________

_____________________________________________________________________________________________________ 
 
 

Specify Your Own Primary Key:

The Rails convention is for every table to have a field named “id” which is an auto-incrementing integer primary key

(that the Rails migration code will automatically insert into your tables). 

If you are working with an existing database, you probably don’t want to redefine all the primary key fields to suit Rails. 
 

In your Migration code, just use the “:primary_key =>” parameter in your create_table method call, like this: 
 

class CreateAppTables < ActiveRecord::Migration

  def self.up

    create_table “employees”, :force => true, :primary_key => “empPK” do |t|

      t.column “empFirstName”,    :string,    :limit => 100, :default => “”,   :null => false

      t.column “empLastName”,     :string,    :limit => 100, :default => “”,   :null => false

      t.column “empActive”,       :boolean,                  :default => true, :null => false

      t.column “empDateCreate”,   :timestamp,                                  :null => false

      t.column “empLastLogon”,    :datetime,                                   :null => false

      t.column “empCustomerMgr”,  :integer,   :limit => 5,   :default => 0,    :null => false

    end

end 

Note – Since you are specifying the primary key, DO NOT also list the primary key as a field !!!

Notice above that since “empPK” is the primary key field, no “t.column” line exists for the field “empPK”. 
 
 

In your Model code, you must also tell Rails not to use the standard “id” primary key. 

Include a statement like this in your model code: 

class Employee ActiveRecord::Base 

  set_primary_key “empPK” 

end 
 
 
 

________________________________________________________________________________________________

________________________________________________________________________________________________ 
 
 

(see also) http://redhillconsulting.com.au/rails_plugins.html 
If you use any engines, etc. that have their own migrations,  

You will need to edit them to keep the “Row Version Migration” plugin from inserting the extra columns. 

In the create table statement, include  :row_version => false 
 

You will also need to edit the field definitions for any field that ends with “id” to keep the “Foreign Key Migration” plugin

from trying to force foreign key constraints on the table. 

Add the following to the end of the each “id” field definition  :references => nil 
 

________________________________________________________________________________________________

________________________________________________________________________________________________ 
 
 

Examples

This migration will add a boolean flag to the accounts table and remove it again:

    class AddSsl < ActiveRecord::Migration
        def self.up
          add_column :accounts, :ssl_enabled, :boolean, :default => 1
        end 
        def self.down
          remove_column :accounts, :ssl_enabled
        end
    end 

Example of a more complex migration that also needs to initialize data:

  class AddSystemSettings < ActiveRecord::Migration

    def self.up

      create_table :system_settings do |t|

        t.column :name,     :string

        t.column :label,    :string

        t.column :value,    :text

        t.column :type,     :string

        t.column :position, :integer

      end 

      SystemSetting.create :name => “notice”, :label => “Use notice?”, :value => 1

    end 

    def self.down

      drop_table :system_settings

    end

  end 
 
 
 

EXAMPLE1:

class CreateRepairs < ActiveRecord::Migration

  def self.up

    execute “DROP TABLE IF EXISTS `repairs`” 

      create_table(:repairs, :force => true :o ptions => ‘ENGINE=MyISAM’) do |t|

            t.column :o rdPK, :integer, :null => false, :auto_increment => true

            t.column :o rdCustPK, :integer, :null => false

            t.column :o rdCustPONum, :string, :limit => 20, :default =>

            t.column :o rdTotal, :decimal, :precision => 10, :scale => 2 :default => ‘0.00′

      end

  end 

  def self.down

    drop_table :repairs

  end

end 
 

EXAMPLE2:

class CreateRepairs < ActiveRecord::Migration

  def self.up

      create_table(:repairs, :force => true) do |t|

            t.column :o rdPK, :integer, :default => 0, :null => false

            t.column :o rdCustPONum, :string, :limit => 20, :null => false

            t.column :o rdFinalDisposition, :string, :limit => 30, :null => false

            t.column :o rDateOrderTaken, :date, :null => false  

            t.column :o rdItemWeight, :decimal, :precision => 10, :scale => 0, :default => 0

            t.column :o rdShippingWeight, :float, :limit => 25, :default => 0, :null => false

    end

  end 

  def self.down

    drop_table :repairs

  end

end 
 
 

Not all migrations change the schema. Some just fix the data:

  class RemoveEmptyTags < ActiveRecord::Migration

    def self.up

      Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? }

    end 

    def self.down

      # not much we can do to restore deleted data

      raise IrreversibleMigration

    end

  end 

Others remove columns when they migrate up instead of down:

  class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration

    def self.up

      remove_column :items, :incomplete_items_count

      remove_column :items, :completed_items_count

    end 

    def self.down

      add_column :items, :incomplete_items_count

      add_column :items, :completed_items_count

    end

  end 

And sometimes you need to do something in SQL not abstracted directly by migrations:

  class MakeJoinUnique < ActiveRecord::Migration

    def self.up

      execute “ALTER TABLE `pages_linked_pages` ADD  
               UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)”

    end 

    def self.down

      execute “ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`”

    end

  end 
 
 

_______________________________________________________________________________________________

_______________________________________________________________________________________________ 
 

The Next “Migration Number” that needs to be applied, is stored in table “schema_info” field named “version”

Migration For Legacy Tables

Filed under: migration, rails — oomoo @ 1:15 pm

If you already have an application with a database full of tables/data, you can easily create a “migration” that will contain all those tables.  

Please note that if you are going to be actually using Ruby/Rails with the existing database, you should not create a migration.  Just use the existing database.  Migrations are great for moving changes you make during development into a production database, but since you already have a production database that is being managed (I assume) by a legacy application, you’d best leave it alone.

But, if you are moth-balling the old application or creating a parallel application in Ruby/Rails, then you can use the following technique to kick-start your migration file.  It’s also just a cool education about how the migrate code works :)  

(I copied this technique from a blog that I cannot recall at this time.  If I can find it again, I will give the proper credit)

Legacy db:Migration Steps:

  1. Edit the <yourapp>\config\database.yml to use the legacy database (the one full of tables/data)
  2. Opening a ruby command line (and go to your rails application directory).
  3. Type the command:  rake db:schema:dump 
    This will “dump” the schema from the existing database into the file <yourapp>\db\schema.rb.
  4. Then create your new migration file by:
  5. Typing in the command line :  ruby script/generate migration your_schema.
  6. Cut and paste the data from the \db\schema.rb file into your new db\migrate01_your_schema.rb file.
  7. Edit the \config\database.yml back to your normal (rails) database.  (Don’t forget to do this!!!)
  8. You will need to add the following piece of code to each of your create_table lines: :force => true.
  9. Your create_table lines should look like the following: create_table “table_name”, :force => true do |t|.   
       This will force the new migration to take place within your db.
  10. Now, you just run your rake migrate command from the command line and your db will be updated.   (rake db:migrate)

Controllers Broken Down

Filed under: classes, controller, rails — oomoo @ 1:13 pm

Controllers are the core of a web request in Rails.

They are made up of one or more actions that are executed on request and then either render a template or redirect to another action.  
 

An action is defined as a public method on the controller, which will automatically be made accessible to the web-server through Rails Routes.

After executing the code in the method, Controller methods (actions), by default, render a page in the app/views directory corresponding to the name of the controller and action.

For example, the index action of the GuestBookController would render the template app/views/guestbook/index.erb by default after populating the @entries instance variable. 

A sample controller could look like this:  
 

    class OrdersController < ApplicationController
      def index
        @order = Order.find :first
      end
     
      def new
        @order = Order.new 
        @order.ordPK = 3
        @order.ordCustPONum =
      end
    end 
     

Session and Request

Just like when using West Wind Web Connection…

The “Session” object and “Request” object (which are created as part of any HTTP “Get” or “Post”) are passed to the Controller. 

This is how the Controller is able to know the “action” (method) that is to be performed.  It extracts it out of the Request object. 
 

Params[]

A “hash” containing the parameters from the “Request” object (or from the URL).

All request parameters, whether they come from a GET or POST request, or from the URL, are available through the params method which returns a hash.

For example, an action that was performed through /weblog/list?category=All&limit=5 will include { “category” => “All”, “limit” => 5 } in params.  

It’s also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:  

  <input type=”text” name=”post[name]” value=”david”>

  <input type=”text” name=”post[address]” value=”1 main street”> 

A request stemming from a form holding these inputs will include

{ “post” => { “name” => “david”, “address” => “1 main street” } }.  
 

Session

Sessions allows you to store objects in between requests.

This is useful for objects that are not yet ready to be persisted, such as a Signup object constructed in a multi-paged process,

or objects that don’t change much and are needed all the time, such as a User object for a system that requires login.  

The session should not be used, however, as a cache for objects where it’s likely they could be changed unknowingly.

It’s usually too much work to keep it all synchronized — something databases already excel at.  

You can place objects in the session by using the session method, which accesses a hash:  

  session[:person] = Person.authenticate(user_name, password) 

And retrieved again through the same hash:  

  Hello #{session[:person]} 
 

Response

Each action results in a response object, which holds the headers and document to be sent to the user’s browser.

The actual response object is generated automatically through the use of “renders and redirects” and requires no user intervention.  

An “action” may perform a single “Render” or “Redirect”  
 

Render

Action Controller sends content to the user by using one of five rendering methods.

The most versatile and common is the rendering of a template.

Included in the Action Pack is the “Action View”, which enables rendering of ERb templates. It’s automatically configured.  

The controller passes objects to the view by assigning instance variables:  

  def show

    @post = Post.find(params[:id])

  end 

Which are then automatically available to the View:  

  Title: <%= @post.title %> 
 

You don’t have to rely on the automated rendering.

Especially actions that could result in the rendering of different templates will use the manual rendering methods:  

  def search

     @results = Search.find(params[:query])

     case @results

       when 0 then render :action => “no_results”

       when 1 then render :action => “show”

       when 2..10 then render :action => “show_many”

     end

  end 
 

Redirect

Redirects are used to move from one action to another.

For example, after a create action, which stores a blog entry to a database, we might like to show the user the new entry.

Because we’re following good DRY principles (Don’t Repeat Yourself), we’re going to reuse (and redirect to) a show action that we’ll assume has already been created.  

The code might look like this:  

  def create

    @entry = Entry.new(params[:entry]) 

    if @entry.save

      # The entry was saved correctly, redirect to show

      redirect_to :action => ’show’, :id => @entry.id

    else

      # things didn’t go so well, do something else

    end

  end 

In this case, after saving our new entry to the database, the user is redirected to the show method which is then executed

To Create A Controller 

(from Ruby cmd prompt)  ruby script/generate controller myname index 

Creates:

  app/contollers/myname_controller.rb

  app/helpers/myname_controller.rb

  app/views/myname/index.rhtml

  test/functional/myname_controller_test.rb 

To Verify:

   (from Ruby command prompt)  ruby script/server

   (browse to) http://localhost:3000/myname 
 
 

See Also: http://betterexplained.com/articles/intermediate-rails-understanding-models-views-and-controllers/
See Also: http://api.rubyonrails.org/classes/ActionController/Base.html 

*Much of this post was transcribed from a Rails screencast.  I am looking for the source to give credit.

MVC Simple Sample

Filed under: MVC, controller, model, view — oomoo @ 12:45 pm

Assumptions: 

    - MySQL Database named “mydata_development” 
    - Table named my_orders 
     
     

Point YML to correct Database: 

    - File Location:  \config\database.yml 
    development:
      adapter: mysql
      database: mydata_development
      username: root
      password:
      host: localhost 
     
     

Model for Table “my_orders”: 

    - File Location:  \app\models\my_order.rb 
    class MyOrder < Activerecord::Base 
    end 
     
     

Controller: 

    - File Location:  \app\controllers\admin\myorders_controller.rb 
    class MyordersController < ApplicationController
      #scaffold :MyOrder - uncomment to have a full on-the-fly web CRUD scaffold.
     
      def index
        @myorder = MyOrder.find :first
      end
     
      def new
        @myorder = MyOrder.new 
        @myorder.ordPK = 3
        @myorder.ordCustPONum =
      end
    end 
     
     

View: 

    - File Location:  \app\views\myorders\index.rhtml 
    <h1>MyOrder#index</h1>
    <p>Find me in app/views/myorders/index.html.erb</p> 
    <%= @myorder.ordPK %>
    <%= @myorder.ordCustPONum %> 
     

To Run: 

March 6, 2008

A View In Pieces

Filed under: rails, view — oomoo @ 12:05 am

“A View is used to render a particular action of a controller in the browser.”

A “View” can be split into components: a layout, a view, and a partial depending on the complexity of a page.

Layout

The layout is a page template which will be used to render several views. Thus, it is reusable.

It contains some elements such as HTML header and footer, menus, design elements, etc. that you want to be the same across several views.

Layouts are stored in /app/views/layouts/

View

The view is used to render a particular action of our controller in the browser (like index, list, show_detail, edit, etc.).  Views are stored in:
/app/views/<name_of_model>/<name_of_view>.html.erb

Examples:
/app/views/customer/index.html.erb
/app/views/customer/list.html.erb
/app/views/customer/edit.html.erb

Partial
A partial is used to render only a part of a page. It gives you an easy way to generate a common piece of rails code/html over and over, for example, iterating through a list of orders for a customer. In Ruby terms, it is much like a Ruby “block”.  It can be really useful when working with Ajax. (for example, refreshing a a table of items without refreshing an entire page).
Partial filenames always begin with an underscore

Partials are stored in
/app/views/<name_of_model>/_<name_of_partial>.rhtml.erb
/app/views/customer/_customer_list.html.erb
 

Index
If you name your initial view page “index.html.erb”, you do not need to specify it’s name in the browser.

For example, if your view is: \app\views\orders\index.html.erb
browse to http://localhost:3000/orders will display the index page.

If you use some other view filename, you just need to specify that view name in the address.
For example, if your view is: \app\views\orders\list.html.erb
browse to http://localhost:3000/orders/list to display the page

Simple View Example

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN” http://www.w3.org/TR/html4/strict.dtd“>
<html>
  <head>
    <meta http-equiv=“Content-Type” content=“text/html; charset=iso-8859-1″ />
    <title>Orders</title>
  </head>
  <body>
    <h1>Order Detail</h1>
    <p>Find me in app/views/orders/index.html.erb</p>
    Order ID: <%= @order.id %><br/>
    Order #: <%= @order.ordPK %><br/>
    Customer PO #: <%= @order.ordCustPONum %><br/>
  </body>
</html>

View-Related File Locations

Views \app\views\<modelname>\<myviewname>
Helpers \app\helpers\<modelname>_helper.rb
Images \public\images\
Stylesheets \public\stylesheets\
JavaScripts \public\javascripts\
Layouts \app\views\layouts\
Partials \app\views\<modelname>\_<partialname>.rhtml.erb

Link a CSS Stylesheet into the HTML by using:

<%= stylesheet_link_tag mystyle.css” , :media => “all” %>
   
…instead of…
<link href=”style.css” mce_href=”style.css” rel=”stylesheet” type=”text/css” />

Link in Javascript by using:

<%=javascript_include_tag :defaults %>
    
…or…
<%=javascript_include_tag “prototype”, “effects”, “dragdrop”, “controls” %>

*I got much of this post from a web training presentation that I can’t find to give credit, I apologize!

March 5, 2008

Why I Decided To Use Ruby On Rails

Filed under: rails, ruby — oomoo @ 11:44 pm

Many people say that choosing a tool for creating web-based applications is a "personal" decision. Well, for me it was all "business". I am a consultant first, and a programmer second. I have to be able to solve my clients problems, giving them a "best fit" solution as quickly and inexpensively as possible. You have to ask yourself what kinds of clients you have and what are the types and sizes of projects you work on. I work mostly on database applications for small to mid-size companies. This means a small team, short development cycles, and "the database is king". This is an absolutely perfect fit for Ruby on Rails.

I wanted to find a web development "package" that came as close as I could get to using my favorite desktop  tool Visual Foxpro (VFP). Yes, I also use .NET, but it really does not lend itself to the short development cycles and easy maintainability that I need.  I also wanted to push my personal envelope and see if there was life outside of Microsoft.  So, I researched (and used) Python and Django, Pearl, PHP, OpenLaszlo, and Flex/Flash before deciding to use Ruby On Rails.

First, you must note that ALL browser-based "languages" and "application frameworks" end up doing nothing more than feeding a combination of JavaScript, HTML, and XML (AJAX) to the browser. That’s it because that is all that browsers natively understand! If you use Flash, Silverlight, or ActiveX controls, those are pseudo-exceptions to the rule, but have their own baggage.  I have included some Flash into my coding toolbox for certain suitable things like charts and dashboards.

Rails is an "web application framework" that uses the Ruby "language" under the covers. The job of a framework is to hide complexity and pull together additionally required technologies into a cohesive package. Rails integrates and extends core web presentation technologies like JavaScript, HTML, CSS, and XML.  It insulates me from the details of HTTP server conversations.  Rails modules like ActiveRecord let me treat database records like objects, automate testing, perform data migrations, detail data relationships, handle near all my SQL calls, perform logging, have built-in session security, etc. Rails makes it easy to find database records, display them to users, allow users to edit them, validate the input, then save the results back to the database.

But, as with all programming frameworks, when you use a framework, you must "buy in" to certain ways of doing things to really make it shine. If you follow the Rails conventions for naming tables, primary keys, program files, web files, etc. you can do an extraordinary amount of work with very few lines of code. Rails does have builders and generators to help you follow the rules fairly easily. If you are migrating a legacy application, things get a little more verbose, but I have some notes on that in other posts on this blog.

One of the biggest hills I had to climb was learning so many new things all at the same time. I had been writing fat-client HTTP/SOAP applications for years, just using the Internet like a wide-area-network.  I had done very little browser-based development work, so I had to get a better handle on HTML and CSS for page design, JavaScript, XML, the document object model (DOM), MySQL for my database back-end, the Rails framework modules, and finally Ruby for my language.

Then, I had to sort through the different web page design/layout packages, database management applications, and biggest of all, which IDE to use for editing/debugging my applications. Finally, I had to select a hosting site and learn their server management tools.  Luckily, I have background in server management, web server deployment, and Unix/Linux.

I must say, that it has proven to be very exciting and fulfilling.  I stepped out of my comfort zone and I don’t regret it!  We didn’t choose this field of work for comfort now did we?

If you are going to try your hand at Ruby and/or Ruby On Rails and you want some tips-and-tricks to help get you started, just have a look around this blog and the many other fine resources out here on the web.  You can also comment or ask me questions here on my blog and I will be happy to help you any way I can!

« Newer PostsOlder Posts »

Blog at WordPress.com.