Oomoo

March 31, 2008

Is Mac “Perfect” for Rails Development?

Filed under: IDE, Linux, Windows, mac, rails — oomoo @ 5:32 pm
I’ve never been a Mac fanboy. I never actually “owned” a Mac either. In fact, it has always pissed me off the way that many of the Rails development blogs just assumed you were using a Mac or possibly Linux, but never (he whispers) “Windows”. The snide little way they would say “Okay class, open your terminal window and type: /script generate blah blah blah”, just assuming that I had a friggin terminal window and that I didn’t have to type “ruby” first.
Microsoft and I have been joined at the brain for quite a number of years now. It’s not the perfect relationship, I’ll admit. Bill doesn’t really listen to what I have to say like he did when things were all new and exciting. He is not interested in my “feelings”. He never asks, “So, how was your development day today?” Although, for a while, he did ask “where do you want to go today?” There have been times when he has gotten me excited about working on a personal project, just to pull the rug out from under me. Sometimes, we would find something to do together, then he’d just lose interest and walk away. I’d yell, “Oh sure, just walk away. Just like you always do when you aren’t the profit center of attention. Bill… look at me, Bill.. why won’t you even look at me!” But he would just keep on walking, leaving me sitting there with a lap full of J++, RDO, Visual InterDev, or our precious love-child Visual FoxPro.
It wasn’t long ago that Steve really started to entice me. He really shined up his Apple with that IPod, then started wearing down my defenses with the MacBook, the iPhone, then we got to a little bit of iTouch, and finally to OS/X. But, I couldn’t make the move, I had too much to lose and the price of change was just too steep. Then one day, we snuck out and were in the computer store, and he kind of nonchalently steers me over to the Mac section; “just to take a look”, he says. Well, it was all clean and nice, so I walk on over and he starts grinning like a schoolboy. There sat the cutest little machine, “it’s a Mac Mini”, he says to me as he is dropping to one knee, “and it’s cheaper than most PCs… besides Bill will never have to know”. I admit that I was swept up in the emotion of it all, and we ended up walking out there hand-in-hand around an extended 3-year warranty.
Now, Bill and I have been really trying to work things out. He showed me that Steel Sapphire has developed one of the slickest IDE’s available for doing Rails in Visual Studio. Just this afternoon, Bill asked me, “Just what does Steve have on his Mac that I don’t have in my Windows”. He stood there pushing his glasses up waiting for an answer. I sighed, then said “It’s just plain ‘easy’ Bill. You always make everything so complicated, and the Mac is fully loaded for Rails development right off the shelf. I don’t have to slave away installing and configuring over a hot CPU all day long, just to find out that everyone can’t agree on what they want. “
No, I’m not leaving Bill, not yet, I’ve got too much invested. But, now that I have Steve, I just can’t give him up. We have too much in common and we really enjoy being around each other. He just “gets” me. And it may be my imagination, but I think he really listens.  Somebody que the screensaver…
So, if you are new to Rails, or are thinking about learning Rails, you don’t “have” to get a Mac. But, if you want a seamless, easy, and enjoyable experience, if you want peace and harmony between your computer, your O/S, and your development, you owe it to yourself to give one a try. In fact, you could probably go down to your local computer store and create a working Rails application right on the demo machine. Try that on any of the non-Mac models! Ruby, Rails, and lots of Gems are already installed and configured. It just works (the first time)!

March 24, 2008

Getting Started Tips

Filed under: IDE, hosting, rails, ruby — oomoo @ 11:30 am

IDE – Integrated Development Environment

There are many Integrated Development Environments (IDE’s) available for the RoR developer. The choices vary a little across operating systems, but most tools are thankfully cross-platform. I hear the majority of the developers working on the RoR “core” use Mac. I also see lots of posts (especially Ruby ones) by the Linux crowd. Very few posts are Windows-specific. Being technology-agnostic, I actually own Windows, Mac, and Linux computers and devices of all shapes and colors. since I am still heavily involved in desktop apps, The majority of my development work is still done on Windows.

On the Mac, many developers are satisfied to use the text editing programs that ship with the O/S. Having used true Integrated Development Environments for so long, I just cannot live without the ability to design-code-test-repeat in the same environment, call me spoiled. I started my development career programming for DOS, writing “C” programs that had to manually manipulate the video buffer just to show a “form”. I have also done a good bit of Unix/Linux administration, so I am comfortable working from a command-line. But, I must say that the need to have various interfaces and command-prompts for running Apache, MySQL, RAKE, and Ruby made me feel like I was taking two steps back in my efforts to move one step forward on the web.

I am so very grateful and forever in debt to the fine cadre of programmers and development shops that are creating really top-notch IDE tools for Ruby and Rails developers. I am just now starting to see a light at the end of the IDE tunnel.

Ruby In Steel (Visual Studio plugin) (Visual Form Designer)
Steel Sapphire’s “Ruby In Steel” plug-in for Visual Studio has put itself on the cutting edge with their “Visual Form Designer”. That’s right folks, the ability to visually design RoR “forms” right in the IDE. In technical terms, it “smooshes” your view, helper, javascript, and css into what the user will see as the final form. You can then drag-n-drop controls on the “form” visually design it, and still get into the code or html and make edits to those. When you are done, it saves all the changes back to their original parts.

I like the safety of this approach, because it gives you one layer of seperation between the “composite” (smooshed together) form and your actual code. This abstraction allows you to do cool things like export the composite out to your favorite HTML editor, then pull it back in. It is also good, because as it is in beta, the tool has lots of bugs left in it. This is a very ambitious project, so I’ll be patient…. is it done yet?

Even aside from the Visual Form Designer, this is a good tool for straight coding and debugging as well. My big gripe, of course, is that it runs inside Visual Studio, which is a pig and a hog and slow and complex and… well, you get the point. It’s hard to be all things to all people and do any one thing really really well. If you are a Microsoft hugger though, you will think all the “crap” is just the way it is for everyone. Well, not so my friend, which is why you should check out some of these other great tools.

Aptana Studio (with RadRails plugin)
I use Aptana Studio every day. It is fast, clean, and quite comprehensive. Oh yeah, it’s FREE. It’s based on Eclipse and handles all things AJAX with aplumb. It also handles development for Adobe AIR, PHP, and iPhone (and it has a completely javascript server-side) if you need any of those things.

Aptana automatically treats your Rails application and associated sub-directories as a “project”, so there’s no need to create/maintain a project file. The real-time debugging support is excellent as is the ability to find/install new “gems” directly from within Aptana.

Heroku
Heroku is one of the most mind-bending development platforms I have come across. Heroku allows you to code, debug, and run your Rails application using nothing more than your FireFox browser. You can create code, upload/modify your database, and debug from any computer with an Internet connection. It is also “group aware” allowing your programming team to all collaborate within the same development space. Yes, there is source code control and the ability to backup your entire project to your PC anytime you like.

Heroku runs in the Amazon EC2 (elastic computing cloud) that means that server configuration does not exist. Just flip a switch and your Rails app is magically in “production”, nothing extra to configure, update, or support. The “elastic” in EC2 means that it should be quite scalable, allowing you to allocate resources as-needed. All this goodness is currently in Beta, so I don’t have any pricing or comparison statistics on the hosting side. But, even without the hosting, the ability to develop and test your complete Rails application from any PC is very exciting and perhaps the most unique play in the industry!

3rd Rail
3rd Rail is a Ruby/Rails-specific IDE from CodeGear (formerly part of Borland). It is a very nice IDE, but it is very “young” and seemed to lack some of the extra goodies incorporated by some of the more mature contenders. I have used Borland products many times during my development career and have always found them to be very solid and productivity driven. I will need to check back with 3rd Rail in a while to see how they are progressing.

Komodo
I purchased Komodo when I was playing with Python and Django (as part of my journey to find Rails). Komodo is very well respected in the Python community. Although I have not used it, I saw that Komodo also has a RoR plugin. If you are using Python or want to use both Python and Ruby, you should check out Komodo.

.

Development Stack (Ruby, Rails, Apache, MySql, SqlLite, etc.)

If you are lazy (I prefer to think of it as “not expending unnecessary cycles”) or you just want a quick way of trying out this whole crazy Ruby On Rails thing, you will want to use a consolidated “development stack”. This simply means that there is a master installer/configuration tool that, with one download, will install and configure all the pieces that go into making a RoR web development platform work. Once the “master install” is done, you have a tightly integrated installation of Apache, Ruby, Rails, and MySQL (or SqlLite or some other open source database) which includes a nice little interface to start/stop all these pieces as needed.

InstantRails

InstantRails is the tried-and-true one of the bunch. It did go through a short period recently where it was no longer supported. This gave rise to BitNami picking up the mantle. But, then InstantRails was once again revived and updated for Rails 2.0. It remains my choice.

BitNami

I tried BitNami a while back, but had troubles with the integrated install. Once InstantRails supported Rails 2.0, I must admit that I stopped trying BitNami. I may use it on a Virtual PC, just to see if they got all the wrinkles ironed out.

.

Books (be sure to get books covering Rails 2.0)

There are tons of books covering RoR. Here are a few I found very helpful. Each of them comes from a different viewpoint, so you will benefit by reading multiple books by different authors. You never know which one of them will explain a certain thing in just the right way to make your little lightbulb come on!

Why’s Poignant Guide To Ruby (http://poignantguide.net/ruby/) (fee and very entertaining)
Programming Ruby – The Pragmatic Programmer’s Guide (Dave Thomas) (known as “PickAxe”)
Agile Web Development with Rails (Dave Thomas)
Ajax On Rails (Scott Raymond)
Build Your Own Ruby On Rails Application (Patrick Lenz)
Ruby For Rails (David A. Black)
Beginning Ruby – From Novice to Professional (Peter Cooper)
The Rails Way
The Ruby Way
The Ruby Programming Language

.

Web Sites (there are also tons of blogs and such)

For in-depth examples and free code, nothing beats the really greats RoR blogs out there!

But, here is a tiny sampler of some of the more “authoritative” Ruby/Rails websites:

Official Rails Site: http://www.rubyonrails.com/
Official Ruby Site: http://www.ruby-lang.org/en/
Offiicial Blog: http://weblog.rubyonrails.org/
API Reference: http://api.rubyonrails.org/
Rails Wiki: http://wiki.rubyonrails.org/rails

ScreenCasts/PodCasts/Workshops
PeepCode: http://peepcode.com/
Rails PodCasts: http://podcast.rubyonrails.org/
Rails Workshops: http://rubyonrailsworkshops.com/
Ruby Learning: http://rubylearning.com/

*As my daddy used to tell me (on an almost daily basis) “well son, you’re not gonna learn any younger”.

March 11, 2008

Variables Across The MVC

Filed under: MVC — oomoo @ 1:53 pm

Here are some notes about variables, scoping, etc.

Variables in Ruby/Rails are of your fairly standard variety (local, instance, public).  There is another type called “class” or “class instance” variables that get way too much attention for the amount they are used (or not used) in most apps.  If you are learning Ruby/Rails, just ignore Class Variables for now and don’t use them. 

As with most languages/frameworks, it’s the “visibility” of variables that is important.  This is especially true with web-based applications.  Ruby is based on MVC (Model/View/Controller) architecture (see http://betterexplained.com/articles/intermediate-rails-understanding-models-views-and-controllers/ for a good MVC overview)

In the diagram shown at the website referenced above, notice that the Browse interacts with the Controller, which gets data from the Model, then passes it back using the View.

Models, View, and Controllers are just classes.  Rails hides their complexity making them seem like magic, but they are just Ruby classes.

Models        are ActiveRecord classes 
Views         are ActionView classes 
Controllers  are ActionController classes

Controllers and Views have a special arrangement though, since both of them are part of ActionPack.  This means they actually share a codebase.  (see http://ap.rubyonrails.com/ for a thorough a picture and an explanation)

…snippet…  “Action Pack splits the response to a web request into a controller part (performing the logic) and a view part (rendering a template). This two-step approach is known as an action, which will normally create, read, update, or delete (CRUD for short) some sort of model part (often backed by a database) before choosing either to render a template or redirecting to another action.   Action Pack implements these actions as public methods on Action Controllers and uses Action Views to implement the template rendering.  Some of the features, are tied to ActiveRecord, but that doesn’t mean that Action Pack depends on Active Record. Action Pack is an independent package that can be used with any sort of backend.” 

What this means for you, is that instance variables defined in a Controller are visible to any View called by that controller. 

Local Variable

      current_time = Time.now 

      If defined in a Controller, it can NOT be seen from “any” View called by the Controller. 
 

Instance Variable

      @current_time = Time.now 

      Can be seen only from “this” instance of this class

      If defined in a Controller, it can be seen from “any” View called by the Controller. 
 

Class (instance) Variable

      @@current_time = Time.now 

      Can be seen and changed from “any” instance of this class (one variable shared across all instances)

      If defined in a Controller, it can be seen from “any” View called by the Controller. 
 

Public/Global Variable

      $current_time = Time.now 

      Can be seen and changed from “anywhere” 
 
 
 

An Example 
 

\app\controllers\application.rb

$current_time = Time.now     # Global Variable  (visible everywhere) 
 
 

Controller

class OrdersController < ApplicationController

  def index

    @orders = Tblorder.find_recent_orders   # Call Model Method “find_recent_orders” 

    @filter_scope_name = “Recent Orders”   # Set Instance Variable (visible by view) 

    render :action => ‘list’     # Show the View

  end

end 
 

Model

class Order < ActiveRecord::Base 

  @filter_recent_days  = 15     # Instance Variable (NOT visible by view because this is the Model) 

  def self.find_recent_orders

                                                      # “sql” is a local variable  (not visible anywhere else)

    sql = “SELECT * FROM orders where DATEDIFF(curdate(), ordDateOrderTaken) <= “ + @filter_recent_days.to_s

  

    find_by_sql(sql)

  end

end 
 

View

<!– Most of the HTML is in \app\views\layouts\orders.rhtml –> 

<% if @orders.length == 0 then%>

  <p> No Orders Exist.</p>

<% else %>

  <% if @filter_scope_name %>     # Using Instance Variable from Controller

    <caption><%= h @filter_scope_name %></caption>

    Current Time: <%= $current_time %>     # Using Global Variable from file application.rb

  <% else %>

    <caption>Order List</caption>

  <% end %>

<% end %> 

<% for order in @orders -%>

  <%= link_to order.id, :action => ’show’ %> <br />

  <%= order.ordCustPONum %> <br />

  <%= order.ordOEM %> <br />

  <%= order.ordDescription %> <br />

  <%= order.ordModelNum %> <br />

  <%= order.ordSerialNum %> <br />

  <%= order.ordFinalDisposition %> <br />

  <%= order.ordDateOrderTaken %> <br />

<% end %> 
 
 

A Note About Controller Methods

Even though your Controller Instance Variables will be visible to your View, your Controller Methods will not.  You can get around this by placing methods that need visibility to the View in your Controller Helper (app\helpers\orders_helper.rb based on our example above). 

“Model” Relationships

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

Notes about how Relationships work in Rails Models.  I created the examples and pulled some of the notes from the API doc.
 

http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html 
 
 

“belongs_to” – Means “this class is a child of the class that is named in the belongs_to statement”. 

“parent class”  -  Use the mixed case singular form. 

“foreign key field”  -  Use the signular form of the parent class name with _id appended. 
 
 

Example: 

class Order < ActiveRecord::Base

  set_table_name “orders”

  set_primary_key “ordPK” 

  #tblOrders belong to customers, use the orders.ordcustpk field.

  belongs_to :customer, :foreign_key => “ordCustPK” 

  #Orders belong to CustomerContact,

  #but only when the field CustomerContact.custconPrimary = 1

  belongs_to :customercontact,  :conditions => “custconPrimary=1″ 

  #Customer

  belongs_to :shipment, :foreign_key => “ordShipPK”

end 
 

class Customer < ActiveRecord::Base

  set_table_name “customers”

  set_primary_key “CustPK” 

  has_many :o rders, :foreign_key => “ordCustPK”

  has_many :customercontacts, :foreign_key => “custconCustPK”

end 
 

class Customercontact < ActiveRecord::Base

  set_table_name “customercontacts”

  set_primary_key “custconPK” 

  #orders belong to customers, use the orders.ordcustpk field.

  belongs_to :customer, :foreign_key => “custconCustPK” 

  #CustomerContacts has many Orders,

  #  related through Customer, using the key index Orders.ordCustPK.

  #To link Orders to Customer.  (the link from

  #  CustomerContacts to Customers is already specified above)

  has_many :o rders, :through => :customer, :foreign_key => “ordCustPK”

end 
 

class Shipment < ActiveRecord::Base

  set_table_name “shipments”

  set_primary_key “shipPK” 

  #Each Shipment only has one Order (one-to-one relationship)

  has_one :o rder

end 
 
 

One-to-one

Use has_one in the base, and belongs_to in the associated model.

  class Employee < ActiveRecord::Base

    has_one :o ffice

  end

  class Office < ActiveRecord::Base

    belongs_to :employee    # foreign key – employee_id

  end 

One-to-many

Use has_many in the base, and belongs_to in the associated model.

  class Manager < ActiveRecord::Base

    has_many :employees

  end

  class Employee < ActiveRecord::Base

    belongs_to :manager     # foreign key – manager_id

  end 

Many-to-many

There are two ways to build a many-to-many relationship.

The first way uses a has_many association with the :through option and a join model, so there are two stages of associations.

  class Assignment < ActiveRecord::Base

    belongs_to :programmer  # foreign key – programmer_id

    belongs_to :project     # foreign key – project_id

  end 

  class Programmer < ActiveRecord::Base

    has_many :assignments

    has_many :projects, :through => :assignments

  end 

  class Project < ActiveRecord::Base

    has_many :assignments

    has_many :programmers, :through => :assignments

  end 

For the second way, use has_and_belongs_to_many in both models. This requires a join table that has no corresponding model or primary key.

  class Programmer < ActiveRecord::Base

    has_and_belongs_to_many :projects       # foreign keys in the join table

  end 

  class Project < ActiveRecord::Base

    has_and_belongs_to_many :programmers    # foreign keys in the join table

  end 

Choosing which way to build a many-to-many relationship is not always simple. If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.  

Is it a belongs_to or has_one association?

Both express a 1-1 relationship. The difference is mostly where to place the foreign key, which goes on the table for the class declaring the belongs_to relationship. Example:

  class User < ActiveRecord::Base

    # I reference an account.

    belongs_to :account

  end 

  class Account < ActiveRecord::Base

    # One user references me.

    has_one :user

  end 

The tables for these classes could look something like:

  CREATE TABLE users (

    id int(11) NOT NULL auto_increment,

    account_id int(11) default NULL,

    name varchar default NULL,

    PRIMARY KEY  (id)

  ) 

  CREATE TABLE accounts (

    id int(11) NOT NULL auto_increment,

    name varchar default NULL,

    PRIMARY KEY  (id)

  ) 
 
 
 

Partial List of Options:

:class_name – specify the class name of the association. Use it only if that name can’t be inferred from the association name. So has_one :author will by default be linked to the Author class, but if the real class name is Person, you’ll have to specify it with this option.

:conditions – specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as authorized = 1.

:o rder – specify the order in which the associated objects are returned as an ORDER BY SQL fragment, such as last_name, first_name DESC

:foreign_key – specify the foreign key used for the association. By default this is guessed to be the name of the associated class in lower-case and _id suffixed. So a Person class that makes a belongs_to association to a Boss class will use boss_id as the default foreign_key.  
 
 

Examples:

belongs_to :firm, :foreign_key => “client_of”

belongs_to :author, :class_name => “Person”, :foreign_key => “author_id”

belongs_to :valid_coupon, :class_name => “Coupon”, :foreign_key => “coupon_id”, :conditions => ‘discounts > #{payments_count}’

Some Rails Naming Conventions

Filed under: rails — oomoo @ 1:43 pm

Just notes about some of the naming conventions used by Rails.  I pulled this info from various sources and filled in the rest.
 

Model/Class Table/Schema 

    Table (in database) – Plural, with underscores instead of spaces between words  (ie: steering_wheels)
    Model / Class – Singular, first letter Capitalized, CamelCase for models (ie: SteeringWheel) 
    Model/Class      Table/Schema
    Order                orders
    LineItem            line_items
    Person               people
    Address             addresses
    Legacy               legacies
    Mouse               mice 
     
    *Foreign key fields are named…  tablename_id     (i.e.  customers_id, orders_id) 
    *id  (Every table automatically gets a key field of “id”  (just plain old “id”)) 
    *created_at, created_on, updated_at, updated_on  (IF USED, rails will automatically update these fields) 
    *lock_version  (IF USED, automatic field used for “optimistic locking”)  (integer, default=0, null=false) 
    *counter_cache  (field used to save database lookups) 
    *type  (IF USED, allows “single table inheritence”) 
    *mytable_count  (IF USED, allows rails to calculate the # of objects created for the class) (when you define it, make it default to zero) 
    *position    (IF USED, “position” is used when sorting objects in a “acts_as_list” class) 
    *parent_id    (IF USED, foreign key column in an “acts_as_tree” model) 
    *lft and rgt    (IF USED, provides nested set enhanced tree-like functionality “acts_as_nested_set”) 
    quote_value
    template 
     
     

Controllers 

    Class Name           File Name   
    WeblogsController        weblogs_controller.rb
    LineItemsController  line_items_controller.rb 
     
     

Views 

    Folder Name       File Name                                  
    web_logs            index.rhtml  (this is just the default, any number of html files can exist here)
    line_items           index.rhtml   
     
    /app/views/orders/index.rhtml 
    Helper:
          /app/helpers/orders_helper.rb 
          Module Name = OrdersHelper 
    To access the view from a browser, if you are using index.rhtml, you just need to specify the view folder name:
    *If you create a file at app/views/layouts/application.rhtml it will automatically be used as a wrapper around all other layouts. 
     

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”

Older Posts »

Blog at WordPress.com.