Posts Tagged ‘activerecord’

Rails on Windows with JRuby

December 12th, 2009

Getting a working Rails stack on Windows can be a frustrating experience.  Rails was born in the Linux/Unix world so there are many libraries assumed to be on your system, but are not part of a regular Windows OS installation.  Below I share my own personal experience with getting up and running with Ruby and Rails using JRuby, which for me was the best way to go.

Requirements

Note the links above might move or change so you can visit (java.sun.comwww.jruby.org, www.postgres.com) and poke around to find them.

Installing Java and JRuby

This part is very easy.  Just double click the Java installer and follow the directions.  It will install Java to a location in your C:\Program Files (or the location you specify).  Do the same with JRuby.  I like to have JRuby live right under C:\jruby-1.4.0 so it is easy for me to get to (by default it will also go under C:\Program Files).

Now we need to edit our Windows environment and make sure that JRuby and Java can be seen on the path.  You’ll want to go to your Start > Control Panel > System > Advanced system settings and click the Environment Variables button.

Windows Environment VariablesYou might already see a JAVA_HOME value under User variables (and that’s ok).  You might even see one for JRUBY too.  I like to have the environment variables for Java and JRuby available at the system level however.

Click New under the System variables section and add entries for JDK_HOME and JRUBY_HOME as you see in the example on the right.  Click OK when you’re done.

Now open a command prompt window (Start > Accessories > Command prompt) and type in echo %JDK_HOME% and hit enter.  You should see the value you set, do this for (echo %JRUBY_HOME%) as well. Both should return the values you set previously in the Environment Variables window.  The last thing to do is add these values to your PATH.

Return to the Environment Variables window and edit the PATH value under system variables by selecting it and hitting Edit.  Entries are separated by a semi-colon (;) so make sure you add one to the front of the entries you’re adding unless there is one already there:

;%JDK_HOME%;%JRUBY_HOME%

Now after that’s done close and reopen your command prompt window (so that the new values are loaded).  Type echo %PATH% and you should see the two paths at the end of the results:

>> echo %PATH%
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;
C:\Windows\System32\WindowsPowerShell\v1.0\;
C:\Program Files (x86)\QuickTime\QTSystem\;C:\Program Files(x86)\Git\cmd;
C:\Program Files\Java\jdk1.6.0_17;C:\jruby-1.4.0\bin

Now that all our paths seem in order we can further verify everything is working right:

>> java -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01, mixed mode)
>> jruby -v
jruby 1.4.0 (ruby 1.8.7 patchlevel 174) (2009-11-02) (Java HotSpot(TM) 64-Bit)

Welcome to JRuby

At this stage you should have a working copy of JRuby.  JRuby is just like Ruby, except it uses Java and not the MRI/YARV interpreter.  Most of the commands you might be used to on a regular Ruby stack work the same in JRuby, except often you use jruby -S to run your commands rather than ruby.  Let’s start installing a few of my favorite gems:

jruby -S gem install rails haml nokogiri shoulda factory_girl cucumber webrat ^
rspec rspec-rails will_paginate ZenTest redgreen fastercsv RedCloth paperclip ^ 
nifty-generators jruby-openssl

That should be plenty to get you going on most any Rails/Ruby project.  Watch the output as the gems are installed, rarely should you run into trouble.  If a gem is complaining about installing you can add the –platform=java flag to the end to try and force it to install under the Java platform (for example):

>> jruby -S gem install grumpy_gem --platform=java

Connecting to Postgres

You probably can use any Rails supported database, but I prefer Postgres.  It’s a free database that is available on a variety of platforms (much like MySQL) but a little more powerful.  I also find it easier to work with on JRuby so it’s the one I’ll use here.

Run the PostgreSQL installer.  Follow the on-screen directions.  During the installation, however it is important to make sure you install the optional JDBC drivers, don’t forget this step (if you do you will have to run the Postgres Stackbuilder application later and install them).

The installer is going to add a ‘postgres’ user onto your system and require you to restart at some point.  Once the installation is completely finished you can open your command prompt and install the Rubygem for connecting to Postgres:

>> jruby -S gem install activerecord-jdbcpostgresql-adapter

I am not going to go into details about how to set-up users, etc. in Postgres.  You hopefully are familiar enough with database software to know how to do there is plenty of information on the Web to figure this out, just Google it.  Postgres comes with some nice GUI tools that make it easy to do and it is pretty straight forward.

Now there is one caveat with the Postgres ActiveRecord adapters and JRuby.  There’s a known issue with creating and dropping databases in Rails.  So in order to get things like rake db:create:all to work you need to type inside your Rails application root:

>> jruby -S script/generate jdbc

That is pretty much all there is to getting a full stack up and running on Windows.  I have started developing in the past week using JRuby on Windows along with Rubymine as my editor and GIT as my source control.  I’ve been pretty happy with it thus far.  I still enjoy developing most on my MacBook Pro – but it was a fun experience exploring JRuby (I’ve been playing with JRuby and Ant working together).

4-Bit Server VM 1.6.0_17) [amd64-java]C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\Wind
owsPowerShell\v1.0\;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Program Files
(x86)\Git\cmd;C:\Program Files\Java\jdk1.6.0_17;C:\jruby-1.4.0\C:\Users\Nicholas>echo %PATH%
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\Wind
owsPowerShell\v1.0\;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Program Files
(x86)\Git\cmd;C:\Program Files\Java\jdk1.6.0_17;C:\jruby-1.4.0\bin

Enjoy Working with Models using Hirb

November 1st, 2009

Hirb is a simple gem that lets you view objects as table (with their attributes as columns and their data as rows).  Collections are shown as a table.  Installing the gem is easy sudo gem install hirb.  The easiest way to handle including it into IRB is to add it to your .irbrc file in your home directory:

require 'rubygems'
require 'hirb'

Hirb::View.enable

Or you can leave off the last line, which will require you to type that into your console whenever you want it to turn on.  (This is the setting I use, because I am not always working with large data sets, but when I do I turn it on).

Another neat trick is to output your ActiveRecord SQL right into your console.  This is a nice if you’re wanting to optimize queries or you just are curious as to what ActiveRecord is really doing.  You could view the logs, but this puts everything into context.  Also if you don’t see a query happening you know that you’re still working with an in-memory object.  Type the below into your Rails console whenever you want to see SQL queries in-line with your ActiveRecord calls:

>> ActiveRecord::Base.logger = Logger.new(STDOUT)

You’ll end up with a console that looks like the image below.  Pretty nice if you have a lot of model work or just want to better visualize ActiveRecord calls and objects.

Rails console using Hirb and inline logger

Rails console using Hirb and inline logger

Learn More

http://tagaholic.me/2009/03/13/hirb-irb-on-the-good-stuff.html

Rails Sessions

October 13th, 2009

What is a session?

Technically a session is a semi-permanent interactive information exchange between two devices, computers or services.  Many people might not even stop to think about how they work, we use them so ubiquitiously (especially as web developers).

A session in HTTP usually is associated, or referenced, by a session token.  These tokens are typically stored inside a cookie on the browser client.  The actual data that these tokens reference can be stored in the cookie itself (not secure), in a database, or in server memory.  Rails developers like to store their session data either in the database or in memcache (an distributed memory key-value based storage service).  [Actually the full list includes:  PStore, ActiveRecordStore, CookieStore, DRbStore, FileStore and MemoryStore]

Using Sessions in Rails

Using sessions in Rails is pretty trivial.  You simply have to call the session method from inside your controller and assign a value to a key:

session[:user] = { :name => 'Nick', :birthdate => Time.parse('1974-07-04') }

Sessions are stored in Rails as a Base64 encoded Marshal string dump.  This means that anything you’re wanting to store in a session must be serializable by Ruby’s Marshal API.  You also should probably avoid storing any large amounts of data (say a chart or graphic), critical data or objects.  If you store critical data you risk losing it, because the nature of a session is semi-permanent.

You also want to avoid storing objects, but instead store references to those objects (user_id vs. an actual User).  This is especially true of objects that have attributes that are apt to change.  You’ll run into headaches trying to keep the object data in sync with the session data.  Also when you modify an object’s structure you may run into issues with older sessions that still are holding on to the old object structure.  Sharing session data across applications can also be a challenge if you store custom objects.  In short just don’t do it, always reference objects.  It’s however relatively safe to store standard data objects (like String, Hash, Array, Time, etc.)

Setting Up Sessions

Setting up Rails to use sessions is very easy in Rails 2.x.  Look for the /config/initializers/session_store.rb file in your Rails project and modify as necessary.  Below is an example of one using a Memcache store:

ActionController::Base.session = {
  :key         => '_play_session',
  :secret      => '7fb9f9e5a65aed3a6699c6cdfd396313bd'
}
ActionController::Base.session_store = :mem_cache_store

One curious thing, there is no good way to expire sessions in Rails.  If you set the :session_expires in your config ( :session_expires => 20.minutes.from_now) that time is set once and isn’t updated in production mode.  There are some plug-ins that can help (SessionTimeout) or write your own session clean-up code (or sometimes a service does it on their own, like Memcache).

If you are using a DB storage you can setup a cron job ot run periodically, via script/runner:

class SessionCleaner
  def self.remove_stale_sessions
    CGI::Session::ActiveRecordStore::Session
      Session.destroy_all( ['updated_at < ?', 30.minutes.ago] )
  end
end

Learn More

http://www.viget.com/extend/wrapping-rails-session-hash/

http://www.quarkruby.com/2007/10/21/sessions-and-cookies-in-ruby-on-rails

Internationalization (I18n) in Rails

August 12th, 2009

You have a great Rails application.  It’s so popular that folks are asking you publish it in additional languages.  Oh that we could all be so lucky!  It’s a problem faced by many successful projects.  At some point you’re going to need to translate your application into other languages.  Luckfully in Rails it is relatively painless to handle.

I18n Class in Rails

Rails has a special class that you can use to both translate strings and localize date / time objects.  I18n is the main workhorse that provides internationalization support out-of-box.  You can also use different a backend like Globalize2 (either as a complete replacement or hybrid solution).  You can learn more bout the I18n API in the official Rails documentation.

Steps to Consider

Setting up your application to support additional languages you’ll need to think about the following:

  • What is the default locale going to be?
  • Where to keep and how to organize your locale dictionaries?
  • How do you set the locale?
  • How do you preserve the locale for the user’s session?
  • How do you switch locale?

Default Locale and Dictionary Locations

Setting the default locale is easy.  In the Rails config/environment.rb file you will find an option commented out for setting the default locale.  Simply uncomment this line and set the locale to whatever default you desire.

config.i18n.default_locale = :en

While you’re in this file you’ll want to also uncomment the line that defines where the locale dictionaries are kept.  The locale dictionaries are just YAML files that define string replacement. You’ll use these dictionaries to define ActiveRecord date and time formats, counts, and standard validation messages.  It also can be used to define custom strings, used for string replacement. Below is a small sample of a dictionary file:

en:
  hello: "Hello world"

You can find more complete starter dictionaries by Svenfuchs on Github.com.  I use these on my own projects to jump-start the translation process and highly recommend them.

<%= t('hello') %>

You can then use string replacement to facilitate translation, the code above would produce “Hello world” if the site was set to the ‘en’ locale.

en:
hello: “Hello world”

Setting the Locale

The easiest way to set the locale is to have locale passed as params in the request.  You could take more sophisticated approaches using URL prefixes, browser preference settings, etc.  Below the code demonstrates a simple implementation using a locale param:

before_filter :set_locale
def set_locale
  # if params[:locale] is nil then I18n.default_locale will be used
  I18n.locale = params[:locale]
end

With this code in your ApplicationController visits to http://www.mysite.com:3000?locale=fr would load the French dictionary file.

Preserving Locale

Another problem you’ll need to contend with is preserving the locale with each subsequent request.  The most usual way of handling this is to modify the default_url_options to always include the locale parameter:

# app/controllers/application_controller.rb
def default_url_options(options={})
  { :locale => I18n.locale }
end

Switching Locale

You’ll want to give users ways to switch their locale when they visit. I’m not going to go into details on how to do this because your implementation will be custom to you. The most popular is using a simple drop down that will redirect the user to the new url with the new locale parameter set. Another possibility, if you have users log in, is to provide a control panel or setting they can configure and redirect them upon login to the correct language.

More Resources

Good-bye Tedium, Hello Field_Set_Forms

April 12th, 2009

I just published a new plug-in on GitHub (http://github.com/ncancelliere/field_set_forms) which takes the boring chore out of developing web forms.

I don’t know about you but I hate how tedious forms can be. The idea of just providing a field type and linking it to your ActiveRecord attribute is nothing new. There are a dozen different form builders out there. I haven’t seen any that would do everything I wanted though, so I made my own.

Another thing that would always get me is remembering whether or not to mark a field as required. Well this plug-in takes care of that to. It uses ActiveRecord reflection to determine if the field is required, and will automatically put a star next to it if it is. There are some other label generation features as well.

I hope you enjoy it.

ActiveRecord sans Rails

July 1st, 2008

Rails comes with some powerful libraries and modules, one of which is ActiveRecord – an ORM written in Ruby. You don’t have to use Rails to benefit from ActiveRecord. I’ve used ActiveRecord alone in situations where I need to modify a legacy database. Instead of writing SQL scripts (which I’m more prone to make errors on) I write instead a script in Ruby.

Below is an example of using ActiveRecord stand-alone. In this example I had to break-out the first and last names of a single field in a legacy database into a new set of columns. The legacy database used all uppercase for table and column names, so I apologize for the “ugly” symbols.

require 'rubygems'
require 'active_record'

ActiveRecord::Base.establish_connection(
:adapter => 'mysql',
:host => 'localhost',
:username => 'user001',
:database => 'mydemo',
)
class AddFirstLastName < ActiveRecord::Migration
  def self.up
    add_column :ADJUSTERS, :ADFIRSTNAME, :string
    add_column :ADJUSTERS, :ADLASTNAME, :string
  end

  def self.down
    remove_column :ADJUSTERS, :ADFIRSTNAME
    remove_column :ADJUSTERS, :ADLASTNAME
  end
end

class Adjuster < ActiveRecord::Base
  set_table_name "ADJUSTERS"
  set_primary_key "ADID"
end

AddFirstLastName.up
adjusters = Adjuster.find(:all)
adjusters.each do | adjuster |
  m = /^(.*?)(s+S+(s*[JjSs]r.?|s*III)?)?$/.match(adjuster.ADNAME.lstrip)
  adjuster.ADFIRSTNAME = m[1]
  adjuster.ADLASTNAME = m[2]
  adjuster.save
end

ActiveRecord::Base.remove_connection()