Weblog
Begin...Rescue - Starting Over with Ruby/Rails
I'm just a guy, Making the move from a Windows database tool to Ruby on Rails.


A Simple Drill-Down

A Simple Drill Down (list of orders to a single order)

Model

order.rb
class Order < ActiveRecord::Base
  def self .find_all_orders
    find( :all , :order => "id" )
  end
end

Controller
orders_controller.rb
def list
  @orders = Order.find_all_orders
end

Views
List .rhtml
< p > Find me in app/views/orders/ list .rhtml </ p >
< table class = "list" cellpadding = "0" cellspacing = "0">
  <% for order in @orders - %>
    < tr >
      <
td ><% = link_to ( h ( order . id ),
                            : action   => 'show' ,
                            : id => order )
%></ td >
      < td ><% = order . ordCustPONum %></ td >
      < td ><% = order . ordOEM %></ td >
      < td ><% = order . ordDescription %></ td >
      < td ><% = order . ordModelNum %></ td >
      < td ><% = order . ordSerialNum %></ td >
      < td ><% = order . ord Status %></ td >
    </ tr >
  <% end %>
</ table >


Show
.rhtml
< p > Find me in app/views/orders/show.rhtml </ p >
Order #: <% = @order . ord Number %>< br />
Customer PO #: <% = @order.ordCustPONum %>< br />


POSTED BY Just A Guy AT 1/07/2008 11:37 PM  |  0 COMMENTS  |  POST A COMMENT  |  DIGG IT




Using Legacy Table in Rails

Example of using Legacy Tables in Rails

Using "legacy" data does not follow the easy Rails way of doing things, but hey, life never seems to be that perfert most of the time. Since nobody handed me a napkin with a design and say "hey, take this and go learn Ruby/Rails you crazy kid", I have had to learn using tables that are currently still in use in a lan-based application. This is learning the "old fashioned way" (in the snow), which involves falling down a lot and taking a frustratingly long time to do even seemingly simple tasks. But, I have gotten to peak behind the curtain a bit at things I otherwise wouldn't have cared about.

Rails is cool because it hides much of the whackiness of web programming
from you, but it is also frustrating if you think you need to see those details. Usually, you don't really need to see the details, its just that you are ignorant and seeing the details gives us anal-retentive types some false feeling of control. It's like switching between a Windows PC and a Mac. Everytime I use a Mac, my heart skips a beat when I can't bring up Explorer and see all the nitty gritty details of every file on the hard drive. But after time, you realize you don't need to see all that crap, because guess why... it just works.

Do you wanna know the dirtly little secret
about using legacy data with Rails (and ActiveRecord)? It 'aint hard!! That's right, I said it. ActiveRecord is actually flexible enough that you just need to specify the "table name" and "primary key" of your table in your Model.

You can still use all the "generators" and "rake tools".
You will just probably need to tweak the output. The Rails "pluralizer" will assume your table named "Company" is actually named "companies". That's cool, just generate the models and controllers the usual way, then change the file names, model classname, and controller classname name back to what matches your actual table. You will 'educate' (or 'edumacate' as we say in Georgia) ActiveRecord about this change as shown below.

You can turn off pluralization
(for your whole project) by subclassing ActiveRecord and forcing your Models to use your subclass, but this seems drastic to me and can have nasty side-effects on some plugins that use ActiveRecord. What is Pluralization? Here's a good description: http://www.slash7.com/articles/2005/11/17/rails-howto-pluralizing
 
Here is a real example of some tables that I was dealing with (and these are actually pretty clean compared to some)


MySQL tables
 
tblorders
   tblcustomers

   These are MyISAM (not InnoDB) tables.
   They have no foreign keys.
   They do have auto-incrementing Integer primary keys (yippeee).
    I did create a regular index on tblorders.ordCustPK

Primary keys
  tblorders.ordPK          (notice the capitalization, MySQL is case-sensitive)
  tblcustomers.CustPK (notice the capitalization, MySQL is case-sensitive)

The Relationship   (not enforced/constrained in database)
  tblorder.ordCustPK ---refers to---> tblcustomers.CustPK
     ...many orders...                                  ...one customer...


Models
\app\models\tblorder.rb
class Tblorder < ActiveRecord::Base
  set_table_name
"tblorders"   <- table_name
 
set_primary_key
"ordPK"      <- primary_key
 
belongs_to
:tblcustomer , :foreign_key => "ordCustPK"   <- fk

  def self
.find_all_orders
    find(
:all , :order => "ordPK"   <- pk
 
end
  def self
.find_recent_orders
    find_by_sql(
"SELECT * FROM tblorders
                where year(ordDateOrderTaken) = year(current_date)
                order by ordPK desc"
)
 
end
end


class
Tblcustomer < ActiveRecord::Base
  set_table_name
"tblcustomers"   <- table_name
  set_primary_key
"CustPK"        <- primary_key
  
  has_many
:tblorders , :foreign_key => "ordCustPK"   <- :fk
end


Controller
#\app\controllers\tblorders_controller.rb

#- Index -------------------------
def
index
  list
  render
:action =>
'list'
end

#- List --------------------------
def
list
  @tblorders
= Tblorder.find_recent_orders
end

#- Show --------------------------
def show
  @tblorder = Tblorder.find(params[ :ordPK
])   <- pk
end

#- Edit --------------------------
def
edit
  @tblorder = Tblorder.find(params[ :ordPK
]])   <- pk
end

#- Update ------------------------
def
update
  @tblorder = Tblorder.find(params[ :ordPK
]])   <- pk

  if
@tblorder
.update_attributesparams[ :tblorder ]])
    flash[
:notice ] =
'Successfully updated.'
   
redirect_to :action => 'show'
, :ordPK => @tblorder   <- pk
 
else
   
render :action => 'edit'
  end
end


View
  Order #: <%
= @tblorder.ordPK %>&<br />
  Status:
<%= @tblorder.ordStatus %> &<br />
  Customer:
<%= @tblorder.tblcustomer.CustName %> &<br />   <- RELATED DATA!



For a different take on this subject (including using non-incrementing primary keys), see the excellent tutorial at
http://sl33p3r.free.fr/tutorials/rails/legacy/legacy_databases.html

More information can be found at:
http://www.robbyonrails.com/articles/2005/07/25/the-legacy-of-databases-with-rails



POSTED BY Just A Guy AT 12/31/2007 4:30 PM  |  0 COMMENTS  |  POST A COMMENT  |  DIGG IT




What is a Model?

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


POSTED BY Just A Guy AT 12/31/2007 1:50 PM  |  0 COMMENTS  |  POST A COMMENT  |  DIGG IT




Public Models

Public Model Objects -or- Public ActiveRecord Objects

Sometimes you just need a "global" or "public" object that contains data. If you store your "application settings" or "company configuration" information in a database table,then it makes sense that you could use ActiveRecord like you would for any other table.  This allows you to easily read and update the information. It also neatly puts it in a single object instead of spreading it out across a bunch of individual public variables.  Yes, you could use an excellent plug-in like AppConfig, but if you have several application-wide groups of data like "application settings" and "company configuration", they end up all together in one object model (I think). 

For simplicity, let's say I have a table named app_settings that stores a bunch of application-wide settings.  To get a public/global model/activerecord object, I would do the following:

Create a standard Model (\app\models\appsetting.rb)

class AppSetting < ActiveRecord::Base
end  

Create a standard Controller 
(\app\controllers\appsettings_controller.rb)
class AppSettings_ Controller < ApplicationController
  def index
    list
    render
:action => 'list'
  end
  def list
    @ appsettings = AppSetting .find( 1 )
  end
  def
show
    @ appsettings = AppSetting .find(params[ : id ])
  end
end

Add code to your "\app\controllers\application.rb" file:

#If $AppSetting object is empty or does not exist, create it now.
begin
  if
$ AppSetting .nil?
    $ AppSetting = AppSetting .find( 1 )
  end
rescue
  $ AppSetting = AppSetting .find( 1 )
end

Add fields in your "app_settings" table to your Views:

Application Name : <% = $ AppSetting . AppLongName %>
Version : <% = $ AppSetting . AppVersion %>

*Don't forget to restart your application server after modifying application.rb (ruby script/server)
*Don't forget that the names of these models, controllers, and fields are case-sensitive.



POSTED BY Just A Guy AT 12/31/2007 4:27 AM  |  0 COMMENTS  |  POST A COMMENT  |  DIGG IT





MY PROFILE
Name: Just A Guy
Location: Atlanta, GA
I've been programming for over 20 years (started when I was 2). When Microsoft decided to end new releases of my favorite development tool, Visual FoxPro (VFP), I had to decide if I wanted to keep drinking the Redmond Kool-Aid or step off that treadmill. I'm a consultant, so I must be very productive to survive. I found Ruby and Rails. Most of what I post here will be things I had to learn the hard way and how I am making the transition from a Windows-based (mainly) desktop tool to open-source web-based tools. Also see http://oomoo.wordpress.com (begin...rescue is part of the Ruby exception handling)

RECENT POSTS
A Simple Drill-Down
Using Legacy Table in Rails
What is a Model?
Public Models

ARCHIVES
January 01, 2008
December 01, 2007