Tuesday 15 November 2011

Rails 3, Draper, Mongo and will_paginate

You can get mongomapper, will paginate and draper to work together like the demos on (https://github.com/mislav/will_paginate) if you access the models in the controller like below

@models = ModelDecorator.
decorate(Model.paginate(:page => params[:page]))

Friday 14 October 2011

Continuous Integration - Headless JS on CentOS

This was a bit of a pain to get working so I thought I would layout the steps to get Continuous Integration (CI) working on CentOS 5.5 with cruise control, rspec and cucumber when you have javascript scenarios you want to run without a real browser.

Before Cruise Control is set up:

1) Clone the latest version of CC from: http://cruisecontrolrb.thoughtworks.com/documentation to your server. (read the guide, update your database.yml etc...)

2) CC can run standalone so start the server. and add your project(s)

3) If you have apache running you will have to set up a virtual host and set it to run as a proxy to the CI e.g. my configuration is:


ServerAdmin EMAIL_ADDRESS
ServerName DOMAIN_NAME
ErrorLog PATH_TO_ERROR_LOG
CustomLog PATH_TO_CUSTOM_LOG
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]


Thanks TomJ.

4) vim lib/tasks/custom_cc.rake

desc 'Custom curise task for RSpec'
task :cruise do
ENV['RAILS_ENV'] = 'test'

if File.exists?(Dir.pwd + "/config/database.yml")
if Dir[Dir.pwd + "/db/migrate/*.rb"].empty?
raise "No migration scripts found in db/migrate/ but database.yml exists, " +
"CruiseControl won't be able to build the latest test database. Build aborted."
end

# perform standard Rails database cleanup/preparation tasks if they are defined in project
# this is necessary because there is no up-to-date development database on a continuous integration box
if Rake.application.lookup('db:test:purge')
CruiseControl::invoke_rake_task 'db:test:purge'
end

if Rake.application.lookup('db:migrate')
CruiseControl::reconnect
CruiseControl::invoke_rake_task 'db:migrate'
end
end

CruiseControl::invoke_rake_task 'spec'
CruiseControl::invoke_rake_task 'cucumber:ok'
end

After Cruise Control is set up

If all is going well then you should be able to start the builder for that project and it should be running the rspec and cucumber tests suite. Now you hit the requirement of writing the scenarios that require javascript and these are currently failing (not unexpected since we don't have a X11 system or browser installed). There are a couple of ways to get these tests running the method I chose was:

1. Add capybara-webkit and headless to the Gemfile:

group :test, :cucumber do
....
gem 'headless'
gem 'capybara-webkit'
....
end

2. Update the features/support/env.rb. Require headless and start it. Also set the capybara js driver to webkit.

require 'cucumber/rails'
require 'headless'

headless = Headless.new
headless.start

Capybara.javascript_driver = :webkit
Capybara.default_selector = :css
Capybara.server_boot_timeout = 50

ActionController::Base.allow_rescue = false

begin
DatabaseCleaner.strategy = :transaction
rescue NameError
raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end

3. Now on the CI server we need to install some packages for the capybara-webkit gem (I hope you have permission)

sudo yum install -y Xvfb
sudo yum install -y qt4 qt4-devel

4. Almost there. Start the screen or capybara will give you an error like "webkit_server: cannot connect to X server"

Xvfb :1 -screen 0 1024x768x16 -nolisten inet6 &

It should now be running in the background, you can check ps or jobs

5. Kill the builder and reboot the CI app and then push the earlier changes. When you start the builder again all the tests should now run and if you're lucky they may even pass.

Tuesday 16 August 2011

Passenger with multiple ruby versions

Hey guys, been investigating a little, and I think this article is a summary of why its a problem http://robaldred.co.uk/2011/06/running-passenger-with-multiple-different-ruby-versions-apache-nginx-rvm/.

Passenger does not support this yet. So unfortunately we will have to wait for a future passenger until we start using rvm in prod and hopefully until then we will only need REE and wont need things like better unicode support ☃ Anyway I have been playing around with the set up of rvm, rails, nginx and passenger and have it working nicely locally.

On a mac we can start services at boot by creating a plist file. Here is my /System/Library/LaunchDaemons/nginx.plist


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>nginx</string>
<key>Program</key>
<string>/opt/nginx/sbin/nginx</string>
<key>KeepAlive</key>
<true/>
<key>StandardErrorPath</key>
<string>/opt/nginx/logs/error.log</string>
<key>LaunchOnlyOnce</key>
<true/>
</dict>
</plist>




sudo launchctl load -w /System/Library/LaunchDaemons/nginx.plist
and unload respectively. I may create an alias for this.


We can set default rvm with rvm ree --default
and use --passenger flag

rvm use ree
gem install passenger

passenger-install-nginx-module


here is the config with ree and rvm.

/opt/nginx/conf/nginx.conf

passenger_root /Users/crawford/.rvm/gems/ree-1.8.7-2011.03/gems/passenger-3.0.7;
passenger_ruby /Users/crawford/.rvm/wrappers/ree-1.8.7-2011.03/ruby;

This just says use the passenger installed with my ree ruby (as the memory benefits go hand in hand)

There was a little trouble with dependencies and gpg so may revisit this later.

Here is some information on Apache Nginx showdown: http://www.joeandmotorboat.com/2008/02/28/apache-vs-nginx-web-server-performance-deathmatch/.

Maybe we load balance an nginx for slow clients in the future? Will investigate more

Thursday 23 June 2011

Setting Up SSL For Your Local Development Environment

The web server Mongrel does not support SSL on its own, in Production we would use something like Apache, Passenger and a Mongrel Cluster. Apache would deal with the SSL and then pass on a header to each Mongrel server, this allows for many benefits, including performance. However this is not really a lightweight enough for agile development. Instead we can use an Apache server as a proxy server to deal with SSL and to pass on the correct header for Mongrel to understand. Once we have configured our proxy server it sits in front and just passes on all requests, the server can start on a local machines system at bootup and should not need to be restarted, so essentially it is invisible to the developer.

We can still continue to use our Mongrel server by itself with no additional configuration, but we can now configure any API URL calls to the new proxy, normal testing can continue with just the normal Mongrel server for our application.

Creating a Self Signed Certificate

The easiest way to create our certificate and key files is with the following command:

openssl req -new -x509 -nodes -out server.crt -keyout server.key

make sure to add the servername '''localhost''' when it asks for your name (e.g. YOURNAME)

These files can be kept anywhere, for example I keep mine in /home//SSL/

Setting up Apache and Creating our Proxy Virtual Host

First we must make sure Apache2 is installed run the command:

sudo apt-get install Apache2

First lets enable all the modules we will need by running the following commands:

sudo a2enmod proxy
sudo a2enmod headers
sudo a2enmod ssl


Now we must update the proxy module to allow proxy requests from localhost by changing the following lines in /etc/apache2/mods-enabled/proxy.conf


<proxy>
AddDefaultCharset off
Order deny,allow
Allow from localhost
</proxy>


Next we can add a file with the following virtual host in it to /etc/apache2/sites-available

<ifmodule c="">

SSLCertificateFile <path to="" certificate="">/server.crt
SSLCertificateKeyFile <path to="" key="">/server.key

SSLSessionCache none

<virtualhost 443="">
SSLEngine on
SSLProxyEngine on
# This is required to set the header for Mongrel to treat it as the correct request
RequestHeader set X_FORWARDED_PROTO 'https'


ProxyPass / http://localhost:3001/
ProxyPassReverse / http://localhost:3001/
ProxyPreserveHost on

BrowserMatch "MSIE [2-6]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
# MSIE 7 and newer should be able to use keepalive
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

</virtualhost>

</path></path></ifmodule>



We should disable the default site using:

sudo a2dissite default

and enable the new one using:

sudo a2ensite sitename

We can run the following commands to start and stop the Apache server
/etc/init.d/apache2 start
/etc/init.d/apache2 stop
/etc/init.d/apache2 restart

We should be able to view the error logs at:

/var/log/apache2/

Pointing the Application to a local URL

If we want an application, such as the whitelabel application to make secure HTTPS API calls to our main platform locally then we can now configure the API URL as follows:

API_URL = https://localhost:443

Wednesday 15 June 2011

Android, Fedora Core 15

FC15 comes installed with Eclipse Helios. When following the google guide for installing the ADT plugin you might see errors like

missing "org.eclipse.wst.sse.core 0.0.0"

This is because the guide is based on Galileo so to get around this make sure you add http://download.eclipse.org/releases/helios to the add new software section of Eclipse. Now when you try to install the plugin any prerequisites will also be installed.

Next step download the android SDK and update the path in the Eclipse properties. Once you have an AVD set up you should then be able to run your app.

Saturday 28 May 2011

Fedora Core 15 - Dell Studio 15 - Broadcom Wireless internet

Massive problems getting my wireless working on the latest and greatest Fedora Core 15! I was upgrading from FC13 and the previous broadcom-wl drivers were not supported on the new kernel. Here is how I fixed it.

Check that your card is supported
lspci -nn
04:00.0 Network controller [0280]: Broadcom Corporation BCM4313 802.11b/g LP-PHY [14e4:4727] (rev 01)

Download the hybrid driver source http://www.broadcom.com/support/802.11/linux_sta.php
Follow the readme steps to disable any existing configuration

Untar and try to make (this will probably fail do you to an error with the source with the c compiler. To resolve find line 485 and replace
init_MUTEX(&wl->sem);
with
sema_init(&wl->sem, 1);
FYI - I read that on another blog but lost the link.

run make again and this time you should be able to compile. Then make install. You should now be able to get the wireless to work

modprobe lib80211 (required for security)
modprode wl.ko or insmod wl.ko

You should be able to run iwlist scanning etc... to connect now.

To automate the wireless to boot on load I added the commands above to /etc/rc.local
Reboot and you should be good to go.

Thursday 19 May 2011

Using virtual attributes in ruby model.to_xml

If you have virtual attributes that you want to include in your to_xml call then you can override the to_xml on the model and pass the virtual attributes as methods. For example

class ModelName < ActiveRecord::Base
has_one :model_name_2

# real attributes a, b
attr_accessor :c, :d
delegate e, :to => :model_name_2
end

Now an instance (mn) of type ModelName calling to_xml will output

mn.to_xml

115true

Now to override the to_xml to include attributes c, d and e.

class ModelName < ActiveRecord::Base
has_one :model_name_2

class ModelName < ActiveRecord::Base
has_one :model_name_2
# real attributes a, b
attr_accessor :c, :d
delegate e, :to => :model_name_2

def to_xml
super(:methods => [:c, :d, e])
end
end

Now when to_xml is called on the model c, d and e will also be included.

mn.to_xml

115trueAnExamplefrom another model