Sunday, 24 May 2009

installing the mysql gem under leopard

I am building a new dev laptop (an MSI Wind u100 running Leopard!) and got everything going... but getting the mysql gem to install was tricky. I had installed MySQL from a binary DMG install.
The trick was to install the gem like so:
sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

Forcing a different render format

I am writing an OAuth system for FilmAmora for the iphone app (and anything else I guess) to use.
I want to always output xml from the controller that is handling the catalog output... but how to do that!

I came up with this:

  def list
render :template => "/catalogs/list.xml.builder", :content_type => "text/xml"
end


This will always output xml (with the right mime type) no matter what the requested format was.

Monday, 18 May 2009

Creating a new rails app with an old version

After much hunting I found how to do this

gem list rails

to see what versions you have. I need to create a 2.1.2 rails app. you can do that by issueing this command:

rails _2.1.2_ my_app

Sunday, 10 May 2009

cookies and hosts / domains

I have been struggling for weeks with a problem of users being logged in to mysite.com, but not en.mysite.com and es.mysite.com. I posted on Ruby Groups and even tried to hire someone to do the work... but to no avail.
Finally I think I cracked it today.

Two things. First, for some reason doing this didn't work:
  if RAILS_ENV == 'production'
config.action_controller.session = {
:session_key => '_my_session',
:session_domain => '.mysite.com',
:secret => 'xxx'
}
else
config.action_controller.session = {
:session_key => '_my_session',
:session_domain => '.mysite.local',
:secret => 'xxy'
}
end


So, I substituted this into each environment file:
config.after_initialize do
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain] = '.mysite.local'
end


That got my session's having the correct domain set (.mysite.com) meaning that the session was saved across subdomains.

Cookies

But then I encountered a second problem. Cookies.
After switching to hide and seek / show and tell methods to enable me to page cache even pages that had logged in status all over them (more on this in another post) I needed some user info in a cookie. But my cookies were tied to the subdomain!
I was setting the cookies like this:

      cookies[:current_user] = {
:cart_items_count => cart_items_count,
:nothing => 1
}.to_json


I thought, ok I just need to add the domain in:
      cookies[:current_user] = {
:cart_items_count => cart_items_count,
:nothing => 1,
:domain => ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain]
}.to_json


No...this didn't work. Everything was being chucked into the cookies 'value' and not the domain field (same happened if I added in an expires_at key). What was going on?
Aha! It is the json-izing.

So, I moved that out to a seperate variable:
      value = {:cart_items_count => cart_items_count, :nothing => 1}.to_json
cookies.delete :login, :domain => ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain]
cookies[:current_user] = {
:value => value,
:domain => ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain]
}


Now my cookies had the proper domain info and the value was still proper json. And now my users are logged in across sub domains!

Saturday, 21 March 2009

backgroundrb by hostname

I love backgroundrb - the way to run scheduled tasks and async workers. BUT on my setup I wanted to run certain backgroundrb tasks on one machine and certain ones on another (for memory reasons and also for testing).

I couldn't find something that did that so I forked backgroundrb into my own repository on GitHub. You can find it here.

You can now have a config file like this:
# A Sample YAML configuration file
---
:backgroundrb:
:ip: 0.0.0.0 #ip on which backgroundrb server is running
:port: 11006 #port on which backgroundrb server is running
:environment: production # rails environment loaded, defaults to development
:debug_log: true # whether to print debug logs to a seperate worker, defaults to true
:log: foreground # will print log messages to STDOUT, defaults to seperate log worker
# :result_storage: memcache # store results in a mecache cluster, you also need to specify location of your memcache clusters in next section
:persistent_disabled: true # turn this off if your application doesn't use backgroundrb's persistent/enqueued tasks system
:persistent_delay: 10 # the time (seconds) between each time backgroundrb checks the database for enqueued tasks
:per_environment: true

# You specify your worker schedules here
:whatever.local:
:backgroundrb:
:environment: test
:schedules:
:test_worker: # worker name
:test: #worker method
:trigger_args: */5 * * * * * * #worker schedule
:data: whatever

:phils-mac-pro.local:
:backgroundrb:
:environment: development
:schedules:
:test_worker: # worker name
:test: #worker method
:trigger_args: */5 * * * * * * #worker schedule
:data: phil


You can launch backgroundrb with a specific hostname like this:

./script/backgroundrb --hostname=whatever.local


I've created Capistrano tasks that fire up an instance on 2 servers and now they act differently based on hostname.

Sweet!

Friday, 13 March 2009

Generating sitemaps and xml catalogues

One of the things we have to do at FilmAmora is generate a catalogue of our films. This is used in a few ways, but principally to drive our recommendations system.

I stumbled across this great blog entry:
Generating-Sitemaps-With-Rails that not only tells you a very nice way of generating sitemaps but also gave us great ideas for using the same technique to generate our catalogues.

Awesome!

Friday, 13 February 2009

ec2onrails EU

Well, necessity is the mother of invention. We needed new FilmAmora servers to deal with the increasing load. I also wanted to move to EU-based EC2 instances.
That meant rolling our own because I believe there are no publicly available ec2onrails instances that run in the eu-west region.

This was not as easy as I would have liked, so here's a little step by step.

1. Go to Alestic and get the id of the proper eu instance. (At this writing it is ami-ac032bd8)

2. Fire up an instance of this. I use Elastic Fox and you need to set the region to europe then choose this instance.

3. copy your pem's into the instance:
scp -i IDENTITY {cert,pk}-*.pem root@HOSTNAME:/mnt/


4. ssh into the instance
ssh -i IDENTITY root@HOSTNAME


5. Get the build script
wget http://ec2ubuntu-build-ami.notlong.com


6. update so you can get git
apt-get update && apt-get upgrade -y


7. get git
apt-get install git-core


8. get ec2onrails and use the latest branch
git clone git://github.com/pauldowman/ec2onrails.git
cd ec2onrails
git checkout --track -b 0.9.9.1 origin/0.9.9.1


9. Run the build script!
 bash ec2ubuntu-build-ami \
--script /root/ec2onrails/server/build-ec2onrails.sh \
--user YOUR_ACCOUNT_NUMBER \
--access-key YOUR_ACCESS_KEY \
--secret-key YOUR_SECRET_KEY \
--bucket BUKCET_NAME \
--prefix PREFIX \
--location EU


Your account number is the 12 digit number from your amazon access information page.

10. Register the instance
ec2-register bucket/manifest.xml --region eu-west-1


That's it!
You should now be able to go to Elastic Fox and launch and instance of this that will be in Europe!