Ruby on Rails may be the next “Killer-App” for web appliction programmers. Here is a basic recipe for creating your first Rails-based application.
Ruby and Rails make creation of these applications easier than ever before. By prefering convention to configuration, you will find its a lot easier to build an application following Rails’ conventions. However, since that is not always possible, there are workarounds for many of these convetions.
Okay, Intalling Ruby and Rails on your computer can be done by the following links:
The harder part is installing Rails on your Brain. While it was designed to be easy to use, Rails does still require some prerequisite talents and studying. While you can get by without all these at first, its always worthwhile to bone up on these subjects.
This command creates a Rails application structure at a directory under your current one. This creates a “myapp” named application.
$ rails myapp
This creates a directory structure named “myapp” with a slew of files and configurations. The structure is very intuitive and easy to grasp. Here is a table of the directory and basic files. Most of these files may not be there quite yet, they will be created after you “generate” parts of the application later.
| Location | Purpose |
|---|---|
| .app/controllers/application.rb | Application Controller Helper |
| .app/controllers/ccc_controller.rb | Application Controller File |
| .app/helpers/application_helper.rb | View Helper for all views |
| .app/helpers/ccc_helper.rb | View Helpers for controller ccc |
| .app/models/ttt.rb | Model definitions for table ttt (singluar) |
| .config/database.yml | Database Connection Settings |
| ./config/environment.rb | Application Level Settings |
| ./config/environments/eee_rb | Development/Test/Production Settings |
| ./config/routes.rb | Route (URL Naming) Rules |
| ./log/development.log | Framework actions running under development |
| ./test/fixtures/ttt.yml | Testing Records for table ttt |
| ./test/functional/ccc_test.rb | Controller Tests for ccc |
| ./test/mocks/eee/* | Mock-tests for environemtn eee |
| ./test/test_helper.rb | Application test helper module |
| ./test/unit/ttt_test.rb | Unit Tests for module ttt |
| ./vendor/ | 3rd Party logic |
| ./script/console | Interactive (irb) console with app libraries |
| ./script/generate | Generates Ruby code into this framework |
| ./script/server | Runs the webrick web server for development |
Rails applications are primarily database-driven applications, so you will need a database with schema (tables, etc.) to use. While I can not determine your schema, you will need to follow a few convections as part of the Rails way of doing things. Note that these can be worked around, but it will save you work from the onset if you can abide by these rules.
Now, create your database and tables. Rails has a scheme to use 3 databases for an application. You should create at least 2 of them now! The popular databases like MySQL, PostgreSQL, Oracle, and DB2 are suppored. Rails was written to work primarily with MySQL, but feel free to choose a better database. I prefer Postgres for data integrity and licensing issues among other reasons.
$ createdb myapp_development CREATE DATABASE $ createdb myapp_test CREATE DATABASE $ psql myapp_development < myapp/db/myapp.ddl.sql
Now you need to tell rails what the databases are. You can find that in the ./config/database.yml file in your Rails application. It lists database records for development, test, and production. Fill in your database adapter (mysql, postgresql, oracle, db2 or whatever) and connection infomation.
What if you need to connect to a second (or more) databases from your application? Add additional records into your database.yml file for each database. For a “security” database, create this entry for development, test, and production environments.
security_development: adapter: postgresql database: security host: localhost username: allen password: xxxxx
Next, edit the ./config/environment.rb file, just under the ActiveRecord::Base.establish_connection line add a line to connect from your model class to the name you used above. The RAILS_ENV variable contains either development, test, or production, so we can use that to differentiate depending on the environment. Say we have a model “Authorization” that needs to access a table in the security database, so we add:
Authorization.establish_connection "security_#{RAILS_ENV}”
Unknown: Do we have to do this for every table we need to access in non-application databases? Would it create multiple connections or cache the connection by its name? Does the security_test database get deleted and reconstructed during tests?
The ActiveRecord component of Rails is used to model the database in a Ruby Data Framework. This is an essential part of Ruby, but ActiveRecord is not essential to Rails. ActiveRecord utilizes what Ruby does best, integrating Object-Oriented abstact base classes with metaprogramming work.
For each table you wish to add to the model, run the generate command. change the table name into the model name by
$ .script/generate model AccountUser
This adds a file called ./app/models/account_user.rb to the application, containing:
class AccountUser < ActiveRecord::Base end
Do this for every table you wish to add to the application. (Of course, you can share a data model repository between application!) This basic definition gives you full access to a conventions-bases access to the table. At runtime, the dtabase catalogs are queries to yield the table columns and definitions to build upon.
Not every data model conforms to the Rails ways of doing things. So Rails provides the class decorator methods to dynamically change the model class If you don’t follow that gibberish, just watch... its easy to understand.
Each ActiveRecord Class assumes the following:
You can use decorators to override these rules:
class AccountUser < ActiveRecord::Base set_table_name "user_account" set_primary_key "employee_id" end
If your database schema does not match the Rails way of doing things, that’s okay! Sure, it will require a couple lines of work, but even in the end you will still be ahead using Rails.
class Project < ActiveRecord::Base set_table_name "my_table" set_primary_key "project id" end
See? That wasn’t hard!
You can add foreign keys, and inter-table relationships into the records to preserve the integrity and give you easy access to these relationships in your code. You specify the table name in symbol form as the association
class Project < ActiveRecord::Base
belongs_to :portfolio
has_one :project_manager
has_many :milestones
has_and_belongs_to_many :categories
end
Defining these associations defines methods in your ActiveRecord class to access these related tables. Substitute your table or association name for assoc and the plural name for assocs in the list. They will be available for the expected singular or multiple association.
assoc() fetches associated record(s) from the databaseassoc=(record) to assign a a record to that associationassoc.nil? check if the association has a linked record assocs.empty? check if the association has any linked record.assocs.size How many records exist in the association assocs«(record) Adds a record in the associationassocs.delete(record) Deletes a record from the association assocs.find(id) Returns the matching record from the associationassocs.find_all(conditions) Returns the matching records from the associationassocs.build(attributes) Forms an association record object assocs.create(attributes) Builds and saves the association recordWhen defining the association, the following optional parameters may be given when appropriate.
:association_name, names the association, usually the table_name.:order ⇒ “col, cols desc”, sets the order of returned records:conditions ⇒ [”where clause”], Any where-clause additions required:class_name ⇒ RecordClass, to override the implied association class name:foreign_key ⇒ foreign_key_name, override the implied foreign key name:dependent ⇒ parm, what happens to dependent records in the association:destroy or true, destroys (cascade deletes) dependent records:nullify, sets the values to null in the dependent records:exclusively_dependent ⇒true, deletes all dependent records at once from your class:finder_sql⇒“statement”, a complete statement to select rows for the association:counter_sql⇒“statement”, a complete statement to select rows counts for the association:extend ⇒ ModuleName, extends class with external module methods shared between classes:include ⇒ :association, loads a secondary association along with current data
Association records from the database are cached. Subsequent accesses do not hit the database again unless you spefify the force_relead parameter: record.assoc_record(true).