Ruby on Windows Guides - The Book
I use Windows on my everyday work. First thing I do after installing Windows is to set up complete environment for Ruby. In “ancient” days (measuring in computer years, of course) I have used One Click Installer. Later, RubyInstaller came on the scene.
With much better foundations, RubyInstaller simplified Ruby usage and made it look like on Linux, Ruby’s native platform. Key benefit of RubyInstaller over One Click installer was possibility to install Ruby native gems written in C. Switching from commercial VisualStudio, used in One Click Installer, to MinGW build tool-chain in RubyInstaller was crucial decision made by Luis Lavena, great author of RubyInstaller.
After RubyInstaller, one more project appeared with the goal to simplify Ruby on Rails installation and usage on Windows. RailsInstaller. I haven’t tried it, but I’m sure it will help increasing number of Rails users on Windows.
But do you really need installer for Ruby on Rails on Windows? It depends of your attitude. If you are not interested what is going on behind the scenes and just want to be able to start using Rails after few mouse clicks RailsInstaller is definitely for you.
If, on the other hand, you want to know how things work, you should try to install Ruby on Rails without installer. With RubyInstaller installing Ruby on Rails on Windows is, actually, just a matter of issuing
1 2 |
gem install rails gem install sqlite3 |
Of course you might face problems building and installing some gems, primarily because gem authors don’t want to bother with Windows support or simply because gems rely of third party libraries that are not ported to Windows. In any case you can ask for help on RubyInstaller mailing list.
People wonder if Ruby and Ruby on Rails are really usable on Windows. My opinion is that they are. Of course, there are some problems mainly with speed, but I would dare to say that solutions are on the way and hopefully very soon this will not be problem any more. I guess main reason why they are not so widespread on Windows platforms is scepticism and lack of experience.
As one of contributors to RubyInstaller project I noticed same questions are repeated on RubyInstaller mailing list. Mainly because of lack of familiarity with Ruby and RoR on Windows. That’s why I decided to write a book where I tried to give deeper insight on all details about installing and using Ruby and Ruby on Rails on Windows. The Ruby on Windows Guides is still in beta. However it already covers the most important issues and I think all novices and advanced developers can learn something new from it. Work on the book is still in progress so if you have any suggestions, ideas and wishes you can send them as an issue on the GitHub.
If you want to get deeper understanding of Ruby and Ruby on Rails on Windows, find out how to build native gems in several ways or just want to get an idea for what you can use Ruby on Windows go ahead and read the book. Of course I expect your comments, here or on GitHub.
Using Selenium with Cucumber through Webrat or Capybara. Which one to choose?
Introduction
Testing is (or should be) important part of every software development. Over time various testing strategies and supporting tools and frameworks have been developed. Regarding Web development biggest advance has been made in Behavior Driven Development. Consequently many tools for BDD are published and used.
Ruby on Rails framework had great built-in support for testing from the very beginning. As it usually happens, lot of specialised testing tools appeared aside of it and among all of them my favourites are RSpec and Cucumber. The first one for unit and the second for functional tests. Both of them are well integrated with Ruby on Rails and are very easy to set up and start with. Moreover there is no need to use real browsers which results in fast tests execution. Perfect way for BDD.
But what if you have to perform functional tests on non Ruby on Rails applications or your application relies heavily on JavaScript (no matter in which framework it is written)? Luckily Cucumber can be used in that case too. Since Cucumber supports Rails out of the box there is basically no need for some special configuration. On the other hand if a real browser must be used in tests, or functional testing must be done outside of the Rails environment setting up Cucumber can be little tricky but still simple enough. In this article I will focus on this scenario – testing non Rails applications with Cucumber and Selenium.
Using Selenium in Cucumber tests is done through Webrat or Capybara. First we must set up complete environment, and in the first step all necessary gems must be installed:
1 2 3 4 5 6 7 |
gem install launchy gem install rspec gem install cucumber gem install webrat gem install capybara --pre gem install selenium-client gem install selenium-webdriver |
Option —pre is used to install Capybara 0.4.0 rc
Important notice for MS Windows users: Webrat depends on Json gem which installs binaries compiled against Rubyinstaller Ruby 1.8.x version. If you are using 1.9.2 Ruby you must uninstall Json gem and install it again but with --platform=ruby option:
1 2 |
gem uninstall json gem install json --platform=ruby |
Since article focuses on the functional testing outside of Rails we should manually create folder structure that Cucumber expects.
tests
|- features
|- support
|- step_definitions
All .feature files go in the features folder. In the support folder env.rb file should be created and within it all set up must be made. Finally steps are implemented in Ruby files in step_definitions folder.
Webrat
Webrat controls Selenium through Selenium RC (remote control) and selenium-client gem. In order to use Selenium through Webrat put following code in your env.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
require 'cucumber/formatter/unicode' require 'webrat' require 'webrat/core/matchers' Webrat.configure do |config| config.mode = :selenium config.application_framework = :external config.selenium_server_address = '127.0.0.1' if RbConfig::CONFIG['host_os'] =~ /mingw|mswin/ config.selenium_browser_startup_timeout = 60 config.application_address = 'localhost' config.application_port = '3000' end World do session = Webrat::Session.new session.extend(Webrat::Methods) session.extend(Webrat::Selenium::Methods) session.extend(Webrat::Selenium::Matchers) session end |
That’s all if you are running Linux based system. On Windows a little bit more effort must be made. First of all, Webrat usess 0.0.0.0 IP address when it starts Selenium and MS Windows does not like it at all. Secondly it uses /dev/null stream which is not available on MS Windows. Patch is already submitted and you can follow a ticket at Webrat Lighthouse. But until fix is accepted and new version is released, you can take a patch from Github gitst and apply it to Webrat sources.
Besides this patch few more things must be done. Line:
1 2 |
config.selenium_server_address = '127.0.0.1' if RbConfig::CONFIG['host_os'] =~ /mingw|mswin/ |
must be added to the config block as is already shown in the above snippet. Unfortunately selenium-client gem does not recognize Rubyinstaller since it is built using MinGW tools. Therefore one more tiny patch must be made in the selenium-client-1.2.18/lib/nautilus/shell.rb file. Function windows? must be replaced with:
1 2 3 |
def windows? ::RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ end |
You are ready for application testing. By default Selenium will use Firefox and if you want to use other browser (in the example Internet Explorer is set) add following line to config block:
1 |
config.selenium_browser_key = '*iexplore'
|
Capybara
Although Capybara can use Selenium RC, it primarily uses Selenium WebDriver which is still in beta phase but is working good. Since we already installed all necessary gems we can go on with configuring our testing environment. File env.rb should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
require 'rbconfig' require 'cucumber/formatter/unicode' require 'capybara' require 'capybara/dsl' require "capybara/cucumber" Capybara.default_driver = :selenium Capybara.app_host = "http://127.0.0.1:8000/" Capybara.register_driver :selenium do |app| Capybara::Driver::Selenium.new(app, :browser => :firefox) end World(Capybara) |
Setting up Capybara is definitely much easier. But on MS Windows systems, if you want to use Internet Explorer, you still have to patch sources. Authors are already notified about required patch and I believe that new version of selenium-webdriver gem will be released with it. In the meantime you just have to change definition of initialize method in selenium-webdriver-0.0.28/lib/selenium/webdriver/ie/bridge.rb from:
1 |
def initialize() |
to
1 |
def initialize(opts = {}) |
Changing browser is as easy as changing :firefox to :ie or :chrome. Instead of :firefox you can also use :ff and for Internet Explorer :internet_explorer. One more notice about differences if you are switching from Webrat to Capybara. Capybara will reset session after each step. If you do not want that (for example you log in to your application in the first scenario, and do not want to repeat it in each succeeding one) just add:
1 2 |
After do end |
in env.rb file.
With Capybara you are not limited to Selenium WebDriver. If you want to use Selenium RC you just need to configure it in env.rb file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
require 'rbconfig' require 'cucumber/formatter/unicode' require 'capybara' require 'capybara/dsl' require "capybara/cucumber" Capybara.default_driver = :selenium Capybara.app_host = "http://127.0.0.1:9000/" Capybara.register_driver :selenium do |app| # This way we are using Selenium-RC Capybara::Driver::Selenium.new(app, :browser => :remote, :url => "http://127.0.0.1:4444/wd/hub", :desired_capabilities => :internet_explorer) end World(Capybara) |
Conclusion
Both gems for running Selenium as a base for functional tests – Webrat and Capybara are easy to use. Although Webrat needs more patching to work under Windows it has one advantage. It can be used with Mechanize if you do not need real browser and you still want to test non Rails application. But as much as it is advantage for “classic” Web application Mechanize cannot interpret JavaScript. So if you want to include JavaScript testing you either have to use real browser or switch to Capybara.
Capybara, on the other hand, needs significantly less patching on MS Windows systems and it cannot use Mechanize as far as I know. But, from my point of view, it is easier to use then Webrat. Currently it cannot use Mechanize, but it can use Culerity and Celerity for JavaScript testing. Moreover capybara-envjs driver can be used to interpret JavaScript outside of the browser.
Although I’m still not sure which one is better to use, I switched from Webrat to Capybara and I think that tests that use Selenium WebDriver are running faster. There is an initiative for merging these projects into one but I do not know if it will happen and when. I would like to hear what you think. What is your choice: Webrat or Capybara?
ActiveRecord SchemaDumper and MySQL problem
After finishing first version of Rmre and issuing fix gem dependency in version 0.0.2, I got an idea for additional functionality. Why not use Rmre for dumping complete schema with all foreign keys data? What would be possible scenario for using this, one might ask? We have possibility to create ActiveRecord models in order to move to Ruby on Rails where main premise is to keep logic out of database and maintain it in application. Therefore we do not need foreign keys since we already have constraints defined in models.
But what if you cannot move to Ruby on Rails and you only have to change DBE, i.e. instead of MS SQL you must use Oracle? In that case you still have to work with legacy database from PHP or Hibernate in Java and “only” thing you have to do is to make create script for all tables but for another DBE. When database has hundreds of tables with lots of relations this can turn into nightmare, especially if you have to maintain both versions.
Rmre should simplify this. First you use Rmre to dump schema to some file and later you can use ActiveRecord’s capabilities to load it on different DBE. Since loading schema in ActiveRecord is DBE agnostic it should correctly create tables, indices and foreign keys on any database engine. That’s theory and, as usual, practice is a little bit different. On a very first step I’ve faced problem in MySQL database.
Let’s examine database with just a two tables – city and country. Create script would look like (example from Sakila database):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
CREATE TABLE city ( city_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, city VARCHAR(50) NOT NULL, country_id SMALLINT UNSIGNED NOT NULL, last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (city_id), KEY idx_fk_country_id (country_id), CONSTRAINT `fk_city_country` FOREIGN KEY (country_id) REFERENCES country (country_id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE country ( country_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, country VARCHAR(50) NOT NULL, last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (country_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
As can be seen from above script table city has foreign key on table country. Now let’s see what is result of a dump:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
ActiveRecord::Schema.define(:version => 0) do create_table "actor", :primary_key => "actor_id", :force => true do |t| create_table "city", :primary_key => "city_id", :force => true do |t| t.string "city", :limit => 50, :null => false t.integer "country_id", :limit => 2, :null => false t.timestamp "last_update", :null => false end add_index "city", ["country_id"], :name => "idx_fk_country_id" create_table "country", :primary_key => "country_id", :force => true do |t| t.string "country", :limit => 50, :null => false t.timestamp "last_update", :null => false end execute "ALTER TABLE city ADD CONSTRAINT fk_city_country FOREIGN KEY (country_id) REFERENCES country(country_id)" end |
At the first glance this looks good but unfortunately doesn’t work. Problem is that loading this schema through ActiveRecord will create columns city_id in table city and country_id in table country as integer type but column country_id in table city is created as smallint. Defining constraint on columns which are not of same type is not allowed so last statement for altering table fails. At the moment I have no idea how to fix this and any suggestion is very welcome. I still have to check what happens on other DBEs: PostgreSQL, Oracle and MS SQL.
RMRE - rails models reverse engineering gem
Very often I have to work on databases which do not follow ActiveRecord convention and making ActiveRecord models, if number of tables is large, is very slow and boring task. In order to speed up and simplify it I’ve created Rmre gem. Gem is quite simple yet you might find it useful if you want to create fixtures, migrations or simply port application to Ruby on Rails.
So how it works? For each table in the database, gem creates model. Name of the model is created using Rails classify method. Moreover, if table’s primary key is not column named “id” gem sets primary key by adding set_primary_key "primaryKeyColumnName" line to the model. In addition for MySQL, PostgreSQL, Oracle or MS SQL foreign keys are analyzed and for each constraint gem generates belongs_to or has_many lines. Here is model created for table store in Sakila MySQL test database:
1 2 3 4 5 6 7 8 9 |
class Store < ActiveRecord::Base set_primary_key :store_id set_table_name 'store' has_many :customers, :class_name => 'Customer' has_many :inventories, :class_name => 'Inventory' has_many :staffs, :class_name => 'Staff' belongs_to :address, :class_name => 'Addres', :foreign_key => :address_id belongs_to :staff, :class_name => 'Staff', :foreign_key => :manager_staff_id end |
Ruby, Rails and MS SQL server
Setting up Rails and Ruby to use MS SQL server was always painful task. Fortunately things have changed – a lot! With new Rails SQL Server 2000, 2005 and 2008 Adapter and Christian Werner’s ruby-odbc gem you can do it in a few minutes.
If you want to use these gems on Windows grab Ruby installation from RubyInstaller site and be sure to install DevKit prior to installing ruby-odbc.
Versions of ruby-odbc before 0.9999 do not work on mingw based (RubyInstaller) Ruby. Luckily author was very fast and made new version very quickly after I sent him a patch. Thanks Christian!
Both gems work well on Ruby 1.8.6 and 1.9.1 Ruby versions on Windows with old ActiveRecords, but I hope rails adapter will be ported to ActiveRecords 3 soon.
Easy Emacs
First step
In my previous articles I wrote a lot about Emacs, its customization and adjusting it for Ruby and Ruby on Rails development. Although these articles give detailed instructions how to set everything up, following all steps are somewhat cumbersome and require quite a lot of work.
Fortunately there is a solution. Just clone Emacs starter kit from Github and you will be able to develop Ruby and RoR applications in Emacs in just a few simple steps. Emacs starter kit uses Elpa packaging and is very easy to configure. But let’s start from the beginning.
Clone Emacs starter kit with Git, to your empty .emacs.d directory. Be sure that init.el file is in .emacs.d folder. If you do not use Git (do you realize what you are missing?) you can get archived sources if you press download button on Emacs starter kit page on Github. Unpack archive to the .emacs.d and be sure that init.el is in .emacs.d folder.
Emacs starter kit has some packages that are still not in Elpa but you’ll have to install additional packages required for Ruby and RoR. Let’s do it now:
1 |
M-x package-list-packages |
New buffer with list of available packages will open and you can select those you want to install. If you plan to use Emacs for Ruby and RoR you’ll definitely need Rinari. It will install all dependent packages.
There are few other that might come in handy like css-mode, javascript or yasnippet but you can always add them later. If you install yasnippet you should probably need yasnippets-rails, but more about that later. Installing packages is very easy. Just place cursor on the package line and press ‘i’. When you are finished with selection press ‘x’ and packages will be installed. At any time you can press ‘h’ to get quick help for Elpa packaging system. In order to uninstall package you have to press ‘d’ (and ‘x’ after that).
Further customization
When you are done with packages installation just restart Emacs and you are ready to continue work in your favorite language – Ruby and framework – Ruby on Rails :) But what if you want to adjust some settings or keep some of those you set according to my previous articles? Luckily that is easy to do, too.
First create sub-directory in .emacs.d directory with your user name on the system you are using. Put your .el files there and Emacs starter kit will load them automatically during Emacs start up. If you have changed color theme and you’ve used theme from color-theme library put color-theme-library.el in this folder and add, for example, line
1 |
(color-theme-deep-blue) |
to any of .el files in this folder. I keep all my additional settings in customization.el file.
I already mentioned yasnippet and yasnippets-rails packages. Simplest way to install yasnippet library is from Elpa system following above mentioned procedure. Unfortunately yasnippets-rails cannot be installed that way so you should clone it from the Github:
1 |
git clone git://github.com/eschulte/yasnippets-rails.git |
Directory yasnippets-rails should be in the directory with your user name under .emacs.d. Add following lines to your customization.el file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
(add-to-list 'load-path
(concat dotfiles-dir "/<user-name>/yasnippets-rails"))
(add-hook 'ruby-mode-hook ; or rails-minor-mode-hook ?
'(lambda ()
(make-variable-buffer-local 'yas/trigger-key)
(setq yas/trigger-key [tab])))
(require 'yasnippet)
(add-to-list 'yas/extra-mode-hooks
'ruby-mode-hook)
(yas/initialize)
(setq yas/window-system-popup-function 'yas/x-popup-menu-for-template)
(yas/load-directory (concat dotfiles-dir "/<user-name>/yasnippet/snippets"))
(yas/load-directory
(concat
dotfiles-dir "/<user-name>/yasnippets-rails/rails-snippets/"))
(make-variable-buffer-local 'yas/trigger-key)
|
and you will be ready for using new snippets during development.
Final word
My previous articles were based on Rails reloaded package for RoR development in Emacs. It is good library and if you like fancy GUI things you can still use it. There is a new version on Github.
Still, I would recommend trying Rinari that is a package from Elpa. It doesn’t have any GUI features but once your fingers “learn” all shortcuts your RoR development will be much easier and faster.
PDN powered by RoR
It has been a few months since my last post on the old blog powered by Wordpress. All this time I was searching for a blog engine made in Ruby on Rails. It was not easy to decide what to use. I’ve tested Mephisto, Typo, Radiant, Simplelog and several others I cannot remember now. All of them really have a lot of features, but for my needs they are way too complex. What I was searching for is some simple application that I can easily tweak and adjust to my needs. I was about to move to Mephisto or Simplelog when I found Enki.
As soon as I’ve looked into the code I knew that it is the one. Simple, lightweight blogging engine without fancy stuff that I’ll rarely use, yet with all features I need for my own blog. Moreover Enki’s source is on Github and it was easy to make a fork and start to work on my own version. So I did it. I must say it can be used just as it is, but I wanted to give it a new “look and feel”, so I’ve started with changes on a style sheet and didn’t stop there.
Enki handles comments in a very flexible way. In order to post a comment only name and text of a comment must be filled. On the other hand, if commenter wants to give a little bit more data he can use OpenID authentication. Nowadays with all those spammers around, this was not good enough for me. I didn’t want blog overloaded with bunch of stupid messages so I’ve decided to change comments handling a little bit.
There are lot of ways to protect a blog from spam. You can forbid posting comment without authorization. That way everyone must register before he is allowed to post a comment. That’s too much work for commenter and, frankly speaking, for me too. I wanted to make commenting as simple as possible, still under decent level of control. In order to accomplish it I could use reCAPTCHA or Akismet. Both of them are quite good, but I’ve decided to use Akismet. It leaves commenter same level of simplicity as in the original Enki source but every comment must pass spam filter. So I’ve dropped OpenID authentication, downloaded akismet.rb, adjusted comments controller and fixed tests. It was quite simple and easy.
And here it is up and running.
Finally few thoughts about Enki. Although it can be used out of the box, I think very few users will actually install it that way. But if you are RoR fan, and you like to work in Ruby and Ruby on Rails this is the right choice for you. Code is readable and easy to change. It is not over-engineered except in one part – gems. Enki requires cucumber which, on the other hand, requires rspec, rspec-rails, webrat and, optionally, term-ansicolor, nokogiri, builder and few others. For my mind it is a little overhead for such a simple project, but it is definitely neglectable comparing to other good sides of Enki. Lack of support for images uploading might be a limitation in Enki’s usability, but author wanted to keep it simple so this shouldn’t stop you from using it. At the end if you like Ruby on Rails it will be a fun implementing support for it, isn’t it? Go ahead, grab attachment_fu or paperclip and do it.

