Archive

Posts Tagged ‘Rails’

Creating a base project in rails

July 16th, 2009 chad No comments

I spent some time over the last few days working on a base application for rails. The idea is straight forward, reduce the start up requirements of a new project – the authentication mechanism, multiple framework inclusions, css layouts, routing, and seo additions are all setup initially. With these pieces of the application already configured, the focus can be placed on development instead of setup.

** note – I am considering a rails template, but that will be a future addition. For now, the project will consist of several gems and plugins.

Here is a link to the github repository where the code resides. If you are not familiar with github, feel free to reach out to me via my User Voice forum and I will help however I can.

Now for the breakdown…

Testing Frameworks/Tools

RSpec RSpec external link / RSpec-Rails RSpec-Rails external link

Both testing frameworks have been vendored so there is no reason to not test (double negative == positive you will test)

Authentication

Clearance Clearance external link

Opinions: Cucumber, Factory Girl, Webrat
Dependencies: Nokogiri (Webrat)

I have spent too many days considering what authentication framework to use. Restful authentication was a previous choice, which I found to be unmanageable and always requiring another tweak. Another opinion was AuthLogic, which seems to be attracting a following. However, I chose clearance… for now. It was created by the folks at thoughtbot, who have plenty of other tasty projects for inclusion.

So to begin with, all authentication requires a means of sign-up, sign-in, sign-out, and password retrieval. This core functionality is essential in making sure users will be able to use your website. They are embedded into the clearance project. It did not unfortunately include clean SEO routes. Not that a login/logout page needs SEO, but for good measure I changed the routes in clearance to practice between url friendliness. An couple examples are dashes instead of underscores and content text rich urls (think /sign-in versus /sessions/new). All of these items should help make clearance a useful auth mechanism within your project.

Layouts

There is only one layout represented in the project, “public.” It cleans up the sign-xxx page layouts, adding fieldsets into forms, auto margins, padding, font details, and a few other CSS tweaks.

Stylesheets

There are multiple styles within stylesheets directory. The naming is standardized on the layout, so all public layout styles will reside under the stylesheets/public directory The stylesheets tag is added into the public layout using the cache key so all stylesheets will be joined into one file in production

taken from app/views/layouts/public.html.erb

stylesheet_link_tag 'public/layout.css', 'public/default.css',
                    'public/forms.css',
                    :media => 'screen', :cache => 'cache/cache'

Javascript
Prototype, jQuery, and an application js has been added to the project. Prototype is added first, with jQuery.noConflict() afterward to keep jQuery from stepping on prototype. The javascript tag is added into the public layout as well, using cache key for one combined javascript file on your production servers.

taken from app/views/layouts/public.html.erb

javascript_include_tag 'prototype', 'jquery-1.3.2.min', 'application',
                       :cache => 'cache/cache'

As it is setup, all jQuery calls will rely on using the reference jQuery instead of the $ function. jQuery can be configured to work with other libraries too. An example is below.

taken from app/views/layouts/public.html.erb

jQuery(document).ready(function() {
...
});

Seo

Rubaidh Google Analytics Rubaidh Google Analytics external link

What public facing site is finished without adding google analytics integration? Without tracking, we don’t know how effectively the message is at targeting our customer. That said, most websites are using some type of analytics toolset behind the scenes to determine demographic information and find ways of segmenting it. I chose google analytics as it is familiar to most. The only part still required for you is setting up the google analytics account and configuring the key in the file below:

taken from config/environment.rb

Rubaidh::GoogleAnalytics.tracker_id   = 'UA-XXXXX-XX'
Rubaidh::GoogleAnalytics.domain_name  = ''
Rubaidh::GoogleAnalytics.environments = ['production']

Additional SEO

I started an SEO addition to this project that creates a new folder config/seo for localized files of static SEO mappings and uses code in the application.rb file and an initializer config/initializers to pull them into the project. An example configuration has been created as en-us.yml is the project. The idea is to define title, description, keyword, and other meta information in a key/value yml file so it can be used in multiple locales. Dynamic mappings can be made with the function set_meta inside any controller. While I know this idea has some downsides, this is a trial / learning period to see what ideas come to light.

taken from config/initializers/meta_mappings.rb

@@META_MAPPINGS = YAML.load_file(
                  File.join(RAILS_ROOT, "config", "seo", "en-us.yml") )

Geo Mapping

Geokit Geokit external link

Included in the project is the geokit gem. It makes use of multiple geocoders on the web. What is a geocoder? It is an API that allows a person to search for latitude and longitude values for a particular point based on address, ip, or other related information. Google is known by most people trying to learn, but more geocoders can be found at the bottom of the geokit rubyforge website readme.html.

taken from config/environments/development.rb

Geokit::Geocoders::google =
'ABQIAAAA03NbuyzEzQFenBHfN8J8TBQP1sBEw9yUgsSPPDa33Q5sgDohShTabokZ0czZTUODwnLWVkXv-lLvtw'

Pagination

Will Paginate Will Paginate external link

What dynamic website does not have pagination? Unless you have found a perfect searching algorithm, you are likely to need this plugin in your views.

Image Upload

Paperclip Paperclip external link

This is another thoughtbot open source project. It works in combination with ImageMagicK to upload, manipulate, and persist images on the filesystem. A few minor filesystem link tweaks are suggested when using capistrano. That will be covered when capistrano is added to this document. For now, the thoughtbot paperclip url is a good reference for information on use.

Logging

Exception Notification Exception Notification external link

Having a mechanism in the application that brings light to any problems is essential. Exception Notifier is a configuration plugin that automates an email based on controller exceptions. It is setup by adding a line to the config/environment.rb file as seem below. Make sure to add your email address to this line.

taken from config/environment.rb

ExceptionNotifier.exception_recipients = %w(my_email@a.domain.com)

Full-text indexing

ThinkingSphinx ThinkingSphinx external link

Full-text indexing is the goods. It provides an abstract way to say, “search my model.. or models, for all the data inside.” It also makes searching for data less code intensive and faster. ThinkingSphinx is a plugin that can tie directly into the sphinx full-text search engine. For those who are unfamiliar with sphinx, further information will be provided on how to use this plugin and setup the sphinx search engine in a later post.

Deployments

Capistrano

Coming soon!

Suggestions?

Comments and suggestions for improvements, bug fixes, or thrashings are welcome and requested! Please use the User Voice forum that is setup.


Weekly refactoring lessons – part 1

July 3rd, 2009 chad No comments

I decided a few weeks ago to write a weekly reference about lessons learned. The lessons may not necessary be new or ground breaking, but further research into a subject where refactorings can be made. I hope this will help others in the process.

Today, I have 2 refactorings to note:

* note – For ease in understanding, I will be writing all code in Ruby.

(Rails) Enumerable.inject

Iterating collections in many languages can be clumsy and code verbose. For instance, you may see the following code written in the java world. It requires a developer to specifically define a return array, add to it while iterating, and return the value. Each step being a separate line.

def adjective_products
  // define a method to return an array of adjective prefixed products
  adjectives = ["fruity", "frothy", "relaxing"]
  product = "beverage"
  product_names = []

  for adj in adjectives
    product_names << "#{adj} #{product}"
  end

  product_names
end

In Ruby there are many changes that can be made to this code. Let's start by refactoring the for loop from of the equation and replace it with a block. It is not very ruby-like and makes my head hurt as though we are using java.

def adjective_products
  // define a method to return an array of adjective prefixed products
  adjectives = ["fruity", "frothy", "relaxing"]
  product = "beverage"
  product_names = []

  adjectives.each { |adj| product_names << "#{adj} #{product}" }

  product_names
end

That's better... at least for now. We have eliminated two lines of code and maybe even made the code seem more readable? However, we still are required to setup an initial variable, iterate the collection capturing values, and finally return that value. In the next refactoring, we will remove the need for this variable by taking advantage of the inject method on the adjectives array.

def adjective_products
  // define a method to return an array of adjective prefixed products
  adjectives = ["fruity", "frothy", "relaxing"]
  product = "beverage"

  adjectives.inject([]) { |acc, adj| acc << "#{adj} #{product}" }
end

To better understand what is happening, let's break down the statement.

First: create a new variable to be returned

Where previously we were defining a product_names array, we are now passing it as a parameter to the inject method

Second: iterate a loop with conditional logic.

The only difference here is the use of the acc, or accumulator, inside inject that is a reference to the array parameter passed into the method.

Third: return a value

From what we already know in ruby, statements will always return the last value set. So the accumulator is being set with each iteration, returning itself. And upon completion of inject, the method will return that accumulator.

Easy enough eh?

(Rails) Range in reverse

This week I had a need to iterate over several already defined columns from a fastercsv row in reverse and return an array of the values. While it can be accomplished in a more declarative way, I wanted to see if it could be done programmatically. So off to Range world I went, starting with the code below:

# comma delimited data
# role_1, role_2,role_3,role_4,role_5
# Admin,System,File
# Admin,System,Dir
# Admin,Web,Save

file_path = "/my/comma/delimited/file"

FasterCSV.foreach( file_path, {
    :headers => true, :skip_blanks => true, :header_converters => :symbol
  } ) do |row|
  row_array = []

  row_array << row[:role_5]
  row_array << row[:role_4]
  row_array << row[:role_3]
  row_array << row[:role_2]
  row_array << row[:role_1]

  row_array.compact!

  # persist the row_array code here (replaced with puts)
  puts row_array.inspect
end

The idea was to iterate rows of comma delimited rows, retrieve a preset number of columns, compact the nils out, and then persist the role data.

So let's start off by removing the declarative code and replace it with a iteration to reduce code.

# comma delimited data
# role_1, role_2,role_3,role_4,role_5
# Admin,System,File
# Admin,System,Dir
# Admin,Web,Save

file_path = "/my/comma/delimited/file"

FasterCSV.foreach( file_path, {
    :headers => true, :skip_blanks => true, :header_converters => :symbol
  } ) do |row|
  row_array = []

  (5..1).each do |i|
    row_array << row[:"role_#{i}"]
  end

  row_array.compact!

  # persist the row_array code here (replaced with puts)
  puts row_array.inspect
end

With that finished, the code should work properly right? Well yes, but unfortunately there is a bug in the way it is written. Notice the range value is from 5 to 1. That is the way the declarative code worked, but the Range object does not. Range objects require a lessor value to a greater value if you want to_a (array) to return anything other than empty.

Try the following for example:

$ irb
irb(main):001:0> (1..5).to_a
=> [1, 2, 3, 4, 5]

Now in reverse:

$ irb
irb(main):002:0> (5..1).to_a
=> []

Oops! What went wrong exactly? Well, Ruby does not iterate in reverse with ranges. They are counter intuitive, but there are two options. I would suggest the later, since it is less to write and definitely more clear as to what is happening.

$ irb
irb(main):004:0> (-5..-1).to_a.collect { |r| r.abs }
=> [5, 4, 3, 2, 1]


$ irb
irb(main):006:0> (1..5).to_a.reverse
=> [5, 4, 3, 2, 1]

Finally to clean up the original code, here is the code after the refactoring. Notice the use of inject too!

# comma delimited data
# role_1, role_2,role_3,role_4,role_5
# Admin,System,File
# Admin,System,Dir
# Admin,Web,Save

file_path = "/my/comma/delimited/file"

FasterCSV.foreach( file_path, {
    :headers => true, :skip_blanks => true, :header_converters => :symbol
  } ) do |row|

  # persist the row_array code here (replaced with puts)
  row_array = (1..5).to_a.reverse.inject([]) { |acc, i|
    acc << row[:"role_#{i}"]
  }.compact!

  # persist the row_array code here (replaced with puts)
  puts row_array.inspect
end

Depending on your level of comfort, this refactoring may not be your cup of tea. While neither manner is absolutely correct, I prefer it over the verbose alternative. It is a decision that is best made by the team. The more readable code is to future eyes, the easier it is to maintain.

Here is a quote from Martin Fowler discussing the use of closure methods like inject:

Now there's a serious question here about a method that complex. (And I must admit I used to be wary of chaining like this.) But it's a good illustration of how useful it is to string these methods together. (And in a language that supports the right kind of concurrency, it has important implications for multi-processor performance.)

Thank you for reading!

Categories: Instruction Tags: , ,

Creating a rails application with rspec

July 3rd, 2009 chad No comments

In this document, you will complete the following tasks:

REQUIREMENTS

Prerequisite knowledge

This instructional document does not require that you understand Ruby on Rails. However, familiarity with osX or Ubuntu (debian) Linux will be helpful. This document is not designed for use with Windows. This instructional document is designed to be completed from top to bottom. More information can be found on this topic at One-Click Ruby Installer.

CREATE A RAILS APPLICATION DIRECTORY

To start with development, we are required to create a rails application directory. Go ahead and execute the following commands:

$ cd /some/directory/for/your/projects
$ rails starter-project
$ cd starter-project

DISCUSS THE RAILS APPLICATION STRUCTURE

Every rails application contains a standard group of directories and files. You can think of this structure as a skeleton for your application. Now let’s discuss each directory and how it is used.

app

Rails follows the Model, View, Controller (MVC) design pattern for developing applications. This directory holds a controllers, models, and views directory. Helpers is available for reuse of code in the rails views.

config

As the directory states, this is where configurations lie

  • Database configurations – database.yml
  • Settings for all environments – environment.rb
  • environments provides a place for development, testing, and production configurations
  • initializers holds files that contain blocks of code run at startup time
  • locales holds localization files
  • Website Url class mappings – routes.rb

db

  • SQLite db files
  • Database Migrations (after first migration is generated)

doc

Document directory

lib

User created libraries.

  • Tasks includes *.rake files for creating rake commands

log

Log files

public

Html, image, javascript, and stylesheet resources

scripts

Commands to start a web server, generate objects, destroy objects, and more

test

Testing for unit, functional, integration, performance and additionally fixtures

tmp

Temporary directory for pids, sessions, etc

vendor

Plugins, Gems, and specific versions of the rails framework

VENDOR RAILS TO A SPECIFIC VERSION

We can save a copy of the rails gems inside our application. The benefits of doing this are keeping a specific version of gems bundled with the application. This helps in deployment and building a development environment on another computer.

$ rake rails:freeze:gems

INSTALL RSPEC AND RSPEC-RAILS GEMS

We will be using rspec for our testing framework. It provides a language centric way of testing where the code is meant to be readable by developers and well as the business/clients.

To install the framework, we need both the rspec and rspec-rails gems. rspec is a spec testing framework for ruby and rspec-rails offers some helpers for rspec in a rails application.

$ sudo gem install rspec
$ sudo gem install rspec-rails

CONFIGURE RSPEC AND RSPEC-RAILS GEMS

Next we need to tell the application how to reference rspec. To do that, add the following lines inside your config/environment.rb file.


# in config/environments/test.rb
config.gem "rspec", :lib => false, :version => ">= 1.2.0"
config.gem "rspec-rails", :lib => false, :version => ">= 1.2.0"

Now regenerate the rspec files

$ script/generate rspec

Your application is now setup with the rspec library! If you wish to continue in this series, the next article will discuss building your models and schema with migrations.

Categories: Instruction Tags: , ,

Setting up your environment for rails

July 2nd, 2009 chad No comments

This instructional document will demonstrate how to prep your computer for developing with the Ruby on Rails framework. It should take no more than 30 minutes to complete.

In this document, you will complete the following tasks:

REQUIREMENTS

In order to make the most of this instructional document, the following operating systems are recommended:

Ubuntu or Mac OS X

http://www.ubuntu.com/
http://apple.com/

Prerequisite knowledge

This instructional document does not require that you understand Ruby on Rails. However, familiarity with osX or Ubuntu (debian) Linux will be helpful. This document is not designed for use with Windows. This instructional document is designed to be completed from top to bottom. More information can be found on this topic at One-Click Ruby Installer.

CHECK TO SEE IF RUBY IS INSTALLED

Let’s start by making certain the ruby language is installed, specifically version 1.8.7. This is usually a part of the osX and Linux operating systems.

Execute the following command:

$ ruby --version

INSTALLING THE RUBY LANGUAGE

If the Ruby language is not installed on your system, you can install this version in two ways:

  1. Installing a pre-compiled package
  2. Compiling the source code

For brevity and an easier upstart, I will use a pre-compiled package. The main package managers in the associated operating systems are “port” (osX) or “aptitude” and “apt-get” (linux). If you are not familiar with either, a simple Google search on the name and the language should help. Using a port on my computer took about 10 minutes.

Install ruby from package (osX)
$ sudo port install ruby

Install Ruby from package (Ubuntu Linux)
$ sudo apt-get install ruby

INSTALL THE RUBYGEMS PACKAGE MANAGER

Next we will install the Ruby package manager. Yes, another package manager just for Ruby! While this may seem overwhelming at first, keep in mind the Rubygems package manager is an integral part of using ruby and rails. It will allow us to install “gems” that are packaged up ruby code that is available from others. Begin by downloading the latest version of rubygems in either *.tgz or *.zip format. After the download is complete, uncompress the file and execute setup.rb. The commands are groups below:

* note – wget is a command that will download the file given to your current directory. You can download it with a web browser, but wget will definitely be faster and keeps our work in the terminal (shell).

$ wget http://rubyforge.org/frs/download.php/57644/rubygems-1.3.4.zip
$ unzip rubygems-1.3.4.zip
$ cd rubygems-1.3.4
$ sudo ruby setup.rb

INSTALLING THE RAILS FRAMEWORK

With gem installed, we are now able to install the rails framework. You can do so by executing the command below. It will install rake, activesupport, actionpack, actionmailer, activeresource, all of which are necessary for rails.

$ sudo gem install rails --no-ri --no-rdoc

INSTALLING SQLITE3

Next, we need to install Sqlite3. It is a text based sql database. It will be how our rails applications store data for and from our webpages. Again, this may already be installed depending on the operating system. We will be going back to port and apt-get for this installation.

Install sqlite3 from package (osX)
$ sudo port install sqlite3

Install sqlite3 from package (ubuntu linux)
$ sudo apt-get install sqlite3

Now install sqlite-ruby bindings with gem
$ sudo gem install sqlite3-ruby

CREATING A NEW RAILS APPLICATION

Finally, let’s finish by creating a new rails application and then start it to see the site.

$ cd /some/directory/for/your/projects
$ rails starter-project
$ cd starter-project
$ ruby script/server

* additionally – if you want the server to start on another port than the default (3000), this script/server command can be executed with the -p attribute

$ ruby script/server -p 8000

Visit the site now running on your computer. This link uses the default port of 3000.

Congratulations, your environment is ready for developing this new rails application! More can be found on creating rails applications in my next article.

Categories: Instruction Tags: , ,
Google Analytics Alternative