Sandbox

From MathsDept

Jump to: navigation, search

Contents

About

This page details some standard elements of Rails development at SIT.

Versions

The Rails setup at SIT are running these versions:

  • Rails 2.0.2
  • Ruby 1.8.6 or 1.8.7
  • Apache 2
  • Passenger (mod_rails for Apache) 2.2.2+

Setting Up A New Rails App

Generate a new Rails application

rails app-name
cd app-name

Remove default index files

cd app-name
rm public/index.html
rm public/images/rails.png

Rails and Subversion

Setting up

Import local Rails project to the subversion repository, where {app-name} is replaced with a name for the project

cd app-name
svn mkdir https://subversion.sfac.auckland.ac.nz/svn/UoA.Science/{app-name}
svn import https://subversion.sfac.auckland.ac.nz/svn/UoA.Science/{app-name}/trunk

Remove the generated Rails application and check out the imported project from svn

cd ..
rm -rf app-name
svn checkout https://subversion.sfac.auckland.ac.nz/svn/UoA.Science/{app-name}/trunk app-name

Set svn to ignore the database.yml, log and tmp files

Don't check into subversion any file that has sensitive information including passwords, such as the database.yml file. Log and tmp files don't need to be version controlled.

Remove config/database.yml from subversion and any other sensitive information. (After performing these steps you'll need to re-add the file, svn will ignore it at this point).

svn remove config/database.yml
svn propset svn:ignore "database.yml" config/
svn update config/
svn commit -m "Ignoring database.yml"

Remove the log files

svn remove log/*
svn commit -m "removing all log files from subversion"

Ignore the log files when they are re-created

svn propset svn:ignore "*.log" log/
svn update log/
svn commit -m "Ignoring all files in log/ ending in .log"

Ignore the tmp directory with all its content (cache, sessions, sockets)

svn remove tmp/* 
svn propset svn:ignore "*" tmp/
svn update tmp/
svn commit -m "Ignoring all files in tmp/"

ActiveRecord Extensions

ActiveRecord:Extensions is a library that extends ActiveRecord's find() method to make it a lot more user-friendly, and allows mass imports of data. It's recommended to include this library in every Rails app you create.

Installation

Note, version 0.7 should be used for Rails 2.0.2 apps. To install:

cd /path/to/rails/app
script/plugin install http://arext.rubyforge.org/svn/tags/ar-extensions-0.7.0

Usage

Extensions to the ActiveRecord find() method:

<source lang="ruby"> Post.find(:all,

 :conditions=> { 
   :rating_ne => 4,                             # rating != 4
   :rating_gt => 4,                             # rating > 4
   :rating_lt => 4,                             # rating < 4
   :author_contains => "Zach",                  # author like '%Zach%'
   :author_starts_with => "Zach",               # author like 'Zach%'
   :author_ends_with => "Dennis",               # author like '%Zach'
   :published_at => (Date.now-30 .. Date.now),  # published_at BETWEEN xxx AND xxx
   :rating => [ 4, 5, 6 ],                      # rating IN ( 4, 5, 6 )
   :rating_not_in => [ 7, 8, 9 ]                # rating NOT IN( 4, 5, 6 )
   :content => /(a|b|c)/                        # REGEXP '(a|b|c)'
 }

) </source>

Importing data:

Note: There's a bug in the 0.7.0 version of ar-extensions where validations will be called before importing, but not other before_ or after_ callbacks (like before_save). The bug has been patched in the Web Booker so you should copy the linked file of that application's ar-extensions plugin and replace before trying to do imports. Search for "luke edit" to read comments on the patch.

<source lang="ruby">

  1. import() can take an array of ActiveRecord objects

imports = [

 ModelObject.new(:name => 'first'), 
 ModelObject.new(:name => 'second')

]

  1. call import() to attempt to save all records in one go

ModelObject.import(imports)

  1. call import() and assign the result to see if there were errors

result = ModelObject.import(imports) result.failed_instances # an array of all ModelObjects that failed to be saved </source>

Security

Security.

Don't check in database.yml or other sensitive information to subversion

config/database.yml contains the database connection details for your application. Make sure that this file, and any file containing passwords, are not checked in to the repository. See the Rails and Subversion wiki page for how to tell subversion to ignore files.

Set robots.txt

As a security step for admin applications, add the following lines to public/robots.txt to ask searchbots not to index the site if ever the authentication layer was to fail.

User-agent: *
Disallow: /

Best Practices

Vendored Gems

If your Rails application requires particular gems to be installed then consider the vendor everything approach, where gems get unpacked into the vendor directory of the Rails application, making deployment simpler.

This will work for all gems that don't need compiling (most of them).

<source lang="bash">

  1. from rails application root

mkdir vendor/gems cd vendor/gems gem unpack [name of gem] </source>

Inside the existing Rails::Initializer block in config/environment.rb of your Rails application, add the following. This will add all libraries in vendor/gems to the Rails load_path making them available to the application:

<source lang="ruby">

Rails::Initializer.run do |config|

 # ...
 config.load_paths += Dir["#{RAILS_ROOT}/vendor/gems/**"].map do |dir| 
   File.directory?(lib = "#{dir}/lib") ? lib : dir
 end
 # ...

end </source>

Use shared models and config files

Folders and files that are shared between a number of Faculty of Science Rails applications have their own svn repository.

These can be included into any Rails application to keep things DRY.

To use

The following is a duplicate of information of the README file in the rails-shared-resource repository.

Add this repository as an external svn repository.

From the Rails application root (note the '.' at the end is important):

<source lang="bash"> svn propset svn:externals "shared https://subversion.sfac.auckland.ac.nz/svn/UoA.Science/rails-shared-resources/" . svn commit -m 'adding svn:externals to rails-shared-resources' svn update </source>

In config/environment.rb on your Rails application, add the following lines near the bottom of the file:

<source lang="ruby">

  1. require all models in the shared folder

Dir["#{RAILS_ROOT}/shared/models/**"].each do |model|

 require model

end

  1. require all files in the lib shared folder

Dir["#{RAILS_ROOT}/shared/lib/**"].each do |library|

 require library

end </source>

If you just want to select certain things to load from a directory, use:

<source lang="ruby">

  1. require these models in the shared folder

models = %w(booking_event_shared ip_shared) Dir["#{RAILS_ROOT}/shared/models/**"].each do |model|

 if models.include?(File.basename(model, ".rb"))
   require model
 end

end </source>

To inherit all methods of a shared model, change your normal Rails model from:

<source lang="ruby"> class [ModelName] < ActiveRecord::Base </source>

to:

<source lang="ruby"> class [ModelName] < Shared::[ModelName] </source>

All methods in the shared model will be inherited and available. You can add application-specific methods to the regular model as normal, including overwriting methods that were in the shared model to redefine them.

Important notes

  • Changes to shared files should be tested between apps after having been committed to the shared repository.
  • Only put generic methods in the shared models. Put things specific to your application in the regular Rails model.

Example use

An example shared model in the shared/models folder

<source lang="ruby"> module Shared

 class Ip < ActiveRecord::Base
   def self.say_hello
     "hello"
   end
 end

end </source>

Your regular Ip model, set to inherit from the shared model

<source lang="ruby"> class Ip < Shared::Ip

 def self.say_hi
   "hi"
 end

end </source>

Will now have two class methods available, as well as interfacing with ActiveRecord

<source lang="ruby"> Ip.say_hello # => "hello" Ip.say_hi # => "hi" Ip.find(:first) # => and all ActiveRecord methods </source>

Write tests

Rails has a test framework built in, which can automate testing of all your models, controllers and views.

See the Unit and Functional Testing for Rails wiki page for more info.

Use rake to write cron tasks

rake is a way of writing task scripts for your Ruby code. Rails comes with a lot of inbuilt rake tasks, and you can write your own. To see the list of rake tasks for any Rails application:

<source lang="bash"> cd /path/to/rails/app rake -T </source>

To execute a rake task from the command line you type:

<source lang="bash">

  1. from the rails application root:

rake api:task_name </source>

To set a rake task up as a cronjob you can use the following format and add it to the crontab:

<source lang="bash"> 0 5 * * * cd /var/wwwdata/applications/wbapi && /usr/bin/rake RAILS_ENV=production api:send_reminders </source>

The above will cd to the Rails application, and run the equivalent of rake RAILS_ENV=production api:send_reminders.

To see some existing rake cronjobs that have been set up, ssh to www7, sudo to bash and crontab -l, and also see the Web Booker API/Developer notes.

For a good tutorial on rake tasks and Rails see this Ruby on Rails and Rake tutorial.

Add a Readme file

Add a file called README.app to the root of the Rails application with a link to the SIT wiki page for the application, development and production sites, svn repository and any other relevant notes. Keep most of the notes in the application wiki page.

Optimisation

SQL Query Reviewer

SQL Query Reviewer plugin inserts a div with plenty of debugging information and recommendations for speeding up slow database queries.

Date optimisation gem

The Ruby Date library is quite slow, and sites that extensively use Ruby Date types (like the Web Booker) might benefit from using the date-performance gem. After requiring it in your config/environment.rb it should seamlessly replace the normal Ruby Date library.

Installation:

<source lang="bash"> gem install date-performance --source=http://tomayko.com </source>

Use:

<source lang="ruby"> require 'date/performance' # or, require 'date/memoize' </source>

Resources and Links

Security

Best Practices

Debugging

Optimisation

See also

Views
Personal tools