Thursday, June 18, 2009

Configuring an Ubuntu server on linode, loaded with rails

Here's a short how-to for getting rails deployed on your linode server.
1. log in to linode
2. generate a public/private key pair on your own system if you havent done so already
3. Click "Deploy a Linux Distribution"
4. Choose one of the Ubuntu releases because I said so
5. leave the defaults
6. choose a root password
7. click "create profile"
8. click "boot" then "ok" on the popup
9. click "console"
10. copy your public key to the text field at the bottom (on one line plz) and click "submit keys to host."
(if you're having trouble finding your public key, do a 'locate *.pub' at a command prompt)
11. Copy the text on the same page that should look something like this: 'ssh linode22231@newark78.linode.com'
12. go to a command prompt (assuming you have ssh installed), enter what you copied and if you pasted your public key correctly in step 10, you should see: 'login:' or something to that effect.
13. Type in 'root' and enter
14. Type in your pass and enter
15. take a break
16. Type in 'apt-get update' to get the latest package lists
17. Type in 'sudo apt-get install gcc'
18. Type in 'sudo apt-get install ruby'

ok, thats a good start...
I'll be back with more later.

Wednesday, June 17, 2009

railsbrain.com

A friend of mine at work pointed me to this gem of a site: railsbrain.com

It has the full rails api with a very nice interface. Also, there's one for just ruby: rubybrain.com. Check them out.

Saturday, May 23, 2009

Creating 'has_many :through' factories with Factory Girl

Factory girl is a great tool for setting up your database for testing. However, I had some trouble when setting up an application that utilizes has_many, :through associations in the models. How do you set up the factories for the two parents and the join table that has its own attributes and still maintain the connection between all three tables? After a couple of days, I solicited the factory_girl list and Josh Clayton pointed me in the right direction, (thanks Josh!)

BTW, I borrowed this particular application from http://www.jumbabox.com/2008/06/ruby-on-rails-many-to-many-tutorial/ if you need more explanation on the models used in this example.

On to the solution:
Here are the models:


class Album < ActiveRecord::Base
has_many :features
has_many :artists, :through => :features
end

class Artist < ActiveRecord::Base
has_many :features
has_many :albums, :through => :features
end

class Feature < ActiveRecord::Base
belongs_to :album
belongs_to :artist
end


As you can see, the Artist and Album models are the parents and the Feature model is the join table. This produces the desired many-to-many association with 'has_many /(:artists|:albums)/, :through => :features'.

Here are the factories... There are two big concepts that should be mentioned that allow this association to be created properly. For one, the associations in the factories should be created from the join table back to the parents. This enables the parents' records to be created at the same time that the join table is created with the link between the three intact.

# revised factories
# created the associations from the join table only
Factory.define(:artist) do |artist|
artist.name "FooFighters"
end

Factory.define(:album) do |album|
album.name "FooTime"
album.genre "FooRock"
album.description "A good time"
end

# join table factory - :feature
Factory.define(:feature) do |feature|
feature.association :artist
feature.association :album
end
The second big concept is that wherever you create your factories (in my case, I'm using cucumber and create the factories in './features/support/env.rb') the parents factories are only @instantiated and returned, though not written to the database. This is done using the 'Factory.build(:factory_name)' method rather than the Factory(:factory_name) or Factory.create(:factory_name) methods. If you used create you would save multiple records to the database with no associations to the join table. When the join table factory is 'create'd, the associations that were defined in the join table factory to the parents create the associated parent's records for you.

Here is how I create the factories in ./features/support/env.rb (NOTE: these factories are created in a Before block that kills all data in the database tables because we want to reset the database as we aren't using transactional fixtures, then reconstructs them with the factories):

Before do
#killing the table data as we aren't using fixtures
Album.destroy_all
Artist.destroy_all
Feature.destroy_all
#recreating the data
# **** Here's the magic ****
# building the parent factories first, and saving them
# through the join table so that the
# the join table record is fully created in db.
album = Factory.build(:album)
artist = Factory.build(:artist)
# using create here as the join table is written to
# the db first with id's from album and artist factories.
# you could use 'feature = Factory(:feature)'
# though using 'create' method for clarity.
feature = Factory.create(:feature)
end
This produces the following output from 'RAILS_ENV=test script/console':
Loading test environment (Rails 2.3.2)
>> @feature = Feature.find(:all)
=> [#Feature id: 8, artist_id: 10, album_id: 8, number_of_songs: nil,
created_at: "2009-05-23 15:03:25", updated_at: "2009-05-23 15:03:25"]
>> @artist = Artist.find(:all)
=> [#Artist id: 10, name: "FooFighters", created_at: "2009-05-23 15:03:25",
updated_at: "2009-05-23 15:03:25"]
>> @album = Album.find(:all)
=> [#Album id: 8, genre: "FooRock", name: "FooTime", description: "A good time",
created_at: "2009-05-23 15:03:25", updated_at: "2009-05-23 15:03:25"]
>>
Great Success!

I hope that was clear... hit me up if you are still having trouble with this.












Sunday, March 15, 2009

Variation on index method from Class String

Ok, so I wanted to find the indices of all occurrences of String 'A' within a larger String 'B'. The Ruby core String class's index and rindex methods do this for one value, but not for all of them.

A recursive solution made the most sense (note: ternary operator has to be on one line):
def indices(str, pos = 0)
!self.index(str, pos).nil? /
? (self.indices(str, self.index(str, pos) + 1) /
| [].push(self.index(str, pos))).sort : []
end
That gives an array of all of the indices in sorted order, and is actually quite cryptic. Here's a more readable version:
def indices(str, pos = 0)
if (!self.index(str, pos).nil?)
# Get the position of the current find
x = self.index(str, pos)
# Return the union of what you found
# and look for more occurrences
[].push(x) | self.indices(str, x + 1)
else
# Basecase. Return empty array for union "|"
[]
end
end

Sunday, March 1, 2009

Heroku gem deployment last resort

If you're having problems installing a gem in your heroku app, check this out as a last resort:

Here's the workaround (commands in bold):
1.) Get a local copy of your app by using the export option on heroku.
2.) Unpack it to a local folder and open up a command line/shell/command prompt.
3.) cd to your app's directory
4.) gem install gemsonrails to get gemsonrails installed to your local gem repo
5.) gemsonrails to install some gemsonrails helpers to your app's environment
5.) rake gems:install GEM=gem_you_want -> gets your gem from the gem cloud in the sky and places it in vendor/gems
6.) rake gems:freeze GEM=gem_you_want -> gets your gem ready for primetime
7.) tar czf myapp.tar.gz myapp/
8.) upload the tar.gz to heroku
9.) sigh with relief because you can now use your favorite gem.