Oomoo

September 2, 2008

Rails Is Not A Language

Filed under: classes, gems, rails, ruby — oomoo @ 2:02 pm

Say it with me… “Rails Is Not A Programming Language”.  Thanks!  It’s easy to forget sometimes that all the magic of Rails is actually riding on a foundation of Ruby.  Rails is a “Web Application Framework” that is written in Ruby.  Ruby actually IS a programming language, Rails is a set of  classes/packages designed to do a lot of the tedious work typically involved in writing a web-based application. 

Ruby is very extensible, owing much to the fact that it is basically compiled on-the-fly.  This means that Ruby can pull in chunks of code as needed and integrate them as new functionality or to augment/override even base functionality.  Usually, these additional pieces of functionality are in the form of “Gems” (get it… Ruby… Gems).  Well, Rails itself is actually just another Ruby Gem (technically a collection of Gems)!  You install Rails (and update it going forward) using the same Ruby commands you would use to install any other Ruby add-on.  I suppose that Rails seems like a language because it actually becomes your interface to Ruby, wrapping Ruby “the language” inside of itself.

The idea behind Rails is to abstract complexity whenever possible, integrate existing 3rd part tools whenever practical, and provide structure, intuitiveness, and design simplicity wherever probable.  Installation of Rails automatically includes the base packages (ActiveRecord, ActionController, ActionView, etc.), a back-end ruby web server called WEBrick, and the JavaScript libraries “Prototype” and “Script.aculo.us” to do the pretty AJAX stuff in the browser.  So, with all of these typically independent pieces neatly wrapped up into one integrated package, it is easy to see why so many people initially mistake Rails for a programming language.

 

The Rails framework does a great job of things like:

  • Giving you the feel of working in an integrated environment.  It does much of this by replacing traditional HTML-only files with a pseudo-HTML file into which you can combine Rails objects and variables and Rails method calls directly (in-line) with your HTML, CSS, and JavaScript.
  • Integration of JavaScript (Prototype and Script.aculo.us) into Rails helper methods hiding some of it’s complexity
  • Taking care of routing web requests
  • Creating secure communication sessions
  • Generating e-mail
  • Ability to generically output to many formats (XML, HTML, etc.) with almost no additional coding
  • Automatic integration of a testing environment for unit and application regression tests

 

Where it really shines is helping you create database applications, since it will help you do things like:

  • Handle database transactions
  • Performing data validation
  • Automatically show/update related records
  • Record locking/detection of stale data
  • Generating automated testing routines
  • Performing SQL without writing pages full of SQL
  • Maintain the state/values of variables and objects between your web pages and your code
  • Performing database record caching inside easy-to-use memory objects. 

 

Rails “encourages” (almost demands) standardized folder structures, file naming, and method naming conventions.  This may feel limiting to some at first, but the payoff is extraordinary.  It infers a level of self-documentation to every project.  It makes it much easier for new developers to join a development team at any stage. It also makes technical documentation and blogs such as this one easier to write because so many things can simply be assumed about the development environment.

The naming standards, request routing, and other basic concepts in Rails afford you some additional cool abilities when it comes time to move/change your application/server/database:

  • instantly move your applications between development, test, and production
  • duplicate/rename an entire application without making any code changes
  • change your back-end database “from” just about any database technology “to” just about any database technology with no code changes
  • change your server-side

 

In Summary…

  • Rails is not a language
  • Ruby is a language
  • “Ruby on Rails” is the official name 
  • “Rails on Ruby” would probably be a more accurate description, but it just doesn’t roll off the tongue as well or sound quite as sexy.

Can you write a Ruby on Rails application without learning Ruby?  It is a testament to the depth of the Rails framework that you actually could write any number of fairly simple web applications without learning a tiddle of Ruby.   You obviously are still “using” Ruby, even if you don’t really understand it.  Doing this, however, would not be a very wise undertaking.  It would be like planting your very first garden without knowing the first thing about dirt, water, sunlight, or (dare I say it) bugs.

 

Wanna try Rails?

Have a Mac?  Rails is built in, see my post:  Is Mac Perfect for Rails Development

Getting Started?  See my post:  Getting Started Tips

Try Ruby without the Rails (in your browser):  Try Ruby

If you want to see some other web frameworks, look here: Wikipedia – List of Web Application Frameworks

March 11, 2008

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.

March 5, 2008

A Model Is A Class

Filed under: classes, model — oomoo @ 11:09 pm

A Model Is A Class

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 :order_account_type
has_many :orders
belongs_to :order_address
belongs_to :order_user
belongs_to :order
 

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

validates_presence_of :order_user_id, :order_address_id, :order_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 free website or blog at WordPress.com.