Vendoring rails using a symlink

Posted by Andrew Premdas Wed, 22 Jul 2009 17:53:00 GMT

Been meaning to do this for ages!

First of all clone rails from git hub into a suitable folder

git clone git://github.com/rails/rails.git rails.git

I like to give repositories like this a .git extension so can easily differentiate from local things, but you can call the folder whatever you want.

After the repository is cloned be sure to checkout the branch you want, in my case git checkout origin/2-3-stable

Now you can vendor your rails projects by going into the root folder of the project and running

ln -s /path_to/rails.git vendor/rails

Adjust the path as required.

Updating Passenger

Posted by Andrew Premdas Wed, 22 Jul 2009 17:18:00 GMT

Updating the passenger gem is a bit of a pain. Its dead easy to just to the gem update and forget to do the other stuff you need to do, especially if you update lots of gems at the same time.

Anyhow after updating passenger be sure to run passenger-install-apache2-module as root. Follow the instructions and update the passenger config (in/etc/apache2/other/passenger.conf on my work box)

Contextual Controllers

Posted by Andrew Premdas Fri, 03 Jul 2009 04:25:48 GMT

I've been struggling alot recently with controllers and with code written by my colleagues. During this period I think I've been making quite a few mistakes. One of the rules I generally like to make about things particularly in software is that if its stupid or doesn't work its probably your fault. This is a really important rule which is real easy to apply to anyone but yourself. So its really easy for me to spot others making mistakes by not applying this rule. When I hear people say Selenium doesn't work, or SASS is rubbish I can comfortably be a wise old owl and think, "ah they should just take a little more time and they will realise that these judgements are made hastily.

Another rule I like to apply is that we (human beings) are mostly ignorant about everything. Socrates (who at the time was considered the wisest of the Greeks) used to tell people seeking his wisdom that he knew nothing. This wasn't some glib bit of rhetoric to reinforce his social status. All his years of study had made him fundamentally aware of how vast knowledge is, how much depth any subject can have, and how little he really did know and understand. This ignorance goes far deeper than just a lack of factual knowledge and goes from the global to the intimate. Using this rule is really dangerous, its so easy to apply it to others and to forget to apply it to yourself, doing this results in smug ignorance. In fact the only value of this rule is self application. It is perhaps a more dangerous expression of the buddhist concept of a "begginers mind"

So what does this have to do with controllers

Well I've been struggling with existing code in our application and in particular with trying to keep code out of controllers. I don't want code in controllers for a number of reasons

  1. They seem to be much harder to spec than models
  2. It seems real easy for various bits of business logic to end up in them - where it is really hard to test
  3. Its real easy for important things like error messages to end up in controllers, and again it feels that this is the wrong place for them
  4. I'm just not comfortable with them, they don't feel like good objects.

Now I've recently been dealing with alot of existing code in controllers that I've not been happy with. In our application we are now treating addresses as a polymorphic nested entity that other entities can have. In addition we have introduced the concept of NamedAddress, which are special in the fact that they have a name and also in the way they persist. Both our controller and views; and our features and steps have struggled to isolate the addressable bit from the relationship with the particular parent.

During this process I've been learning lots, improving the code and generally working really hard on improving quality. Trouble with working really hard is that its really easy to work really stupidly and I've been doing that too. I've also been assuming that existing code is stupid. Take the following code in the index method of the OrdersController

def index
  @pending_orders = @customer.pending_orders
  @completed_orders = @customer.completed_orders
end

I broke this code (well actually the view it shows) by the following refactoring of routes

 map.resources :customers do |customers|
   customers.resources :addresses
   customers.resources :orders
 end

to

 map.resources :customers, :has_many :addresses, :shallow => true 
 map.resources :customers, :has_many :orders, :shallow => true

This is a really stupid refactoring. Why?

So back to this index method which I'm now having to look at because my features are broken. Well its obviously wrong, because its an Order controller with customer code in it. I've just spent ages making sure that my Address controller doesn't have code that refers to a specific parent, and refactored lots of features and in particular steps that should have been Addressable not Customer/Address or Order/Address. And now on top of that there are all these Order features and in particular steps that have @customer in them. So now I'm peeved and am about to start to work even harder to get this stuff sorted when ... I have to go home.

Time passes ... and I realise that "its my fault" and that "I am stupid"

Remember "if its stupid and it doesn't work its probably your fault". Remember that stupid refactoring! and the fact that your added shallow routes to the customer order relationship at the same time as to the customer address relationship. Understand that applying shallow routing will change/break numerous named routes and url generation methods. Realise how stupid it is to do this in for two relationships at the same time. Realise that doing this refactoring for one relationship should be a seperate issue and commit - and here I am trying to do this for two relationships in the middle of doing something else!! Realise that I shouldn't even be looking at the OrdersController never mind making flawed judgements about the code in it. Understand that in the 'shop' part of this application that orders fundamentally belong to a customer and cannot exist without them. Realise that my colleagues implicitly get this possibly due to their greater experience with ecommerce. Realise that if the index method in the OrdersController is flawed its only very minor (perhaps just the customer needs to made available to the view). Realise that controllers are more contextual than models; and that the implied one to one relationship between controllers and models is a figment of my misunderstanding. Realise that a simple one line before filter can express a controllers context and allow a controller to fulfill a significantly different role.

There is lots more, but I'm really tired now.

So once again programming provides that wonderful opportunity to learn, and reinforces the need for my to keep my little rules and diligently apply them to myself.

Using fbrp

Posted by Andrew Premdas Sat, 17 Jan 2009 06:55:38 GMT

FBRP is my rails starter application. When you base an application on it you need another git repository to push the application to. So I have to set up the application in a way that it can get updates from FBRP and yet still be independent.

Base and Master Branches

Most Git apps have a master branch. When you set up a new application from FBRP your master branch will be tied to FBRP. This is not desirable. So instead we create a 'base' branch for fbrp

gch -b base

Now we modify .git/config.

[remote "fbrp"]
    url = git://github.com/diabolo/fbrp.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "base"]
    remote = fbrp
    merge = master

What this does is tie the base branch in our new application to the master branch of FBRP. Now when FBRP is update we can pull directly into the base branch

gch base
git pull

After that we can merge back into the master branch doing a rebase

gch master
git rebase base

Setting up local remote

We can clone our new project and put it on little-un. In the following our new project is 'tc4'

git clone --bare tc4 tc4.git
scp -r tc4.git deploy@little-un:/srv/git

Now we remote into little-un and change permissions

sshlun
sudo chown -R git:git /srv/git/tc4.git/

Finally we go back to our dev box and clone a new project

mv tc4 tc4.old
git clone git@little-un:/srv/git/tc4.git

If we do a

gb -a

We get

* master
origin/HEAD
origin/base
origin/master

If we wish to get updates from fbrp to our new clone we have to create a local base branch and update our .git/config as above

gch -b base

modify .git/config by adding

[remote "fbrp"]
    url = git://github.com/diabolo/fbrp.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "base"]
    remote = fbrp
    merge = master

Now we should have

Branch | Push          | Pull 
------ | ------------- | ------
Base   | no            | yes (little-un) 
Master | yes (github)  | yes (little-un)

Initial Application Steps

  • database.yml
  • update session key in environment.rb
  • update application name and repo location in deploy.rb
  • create local database tables

Then migrate and run

rake spec
rake features

Change Rails Environment when running scripts

Posted by Andrew Premdas Tue, 26 Aug 2008 01:04:46 GMT

Always seem to forget this and take ages finding it again

RAILS_ENV=production script/...

New Rails Project (part 3) - Default Layout

Posted by Andrew Premdas Sat, 12 Jul 2008 19:45:19 GMT

Here we discuss getting a simple structure in place for laying out the pages of our application ...

Using HAML and SASS

Our setup is dependent on HAML and SASS. Lets just add this to the HAML branch first of all and see how things go.

gch haml

We are going to add some SASS stylesheets but first of all we'll use a reset style sheet.

Our SASS stylesheets will separate 3 concerns

  • layout
  • typography
  • appearance

Layout

Layout comprises of two sass stylesheets, grid-base and structure.

grid-base defines a virtual grid using SASS arithmetic, which by default is divided into 24 columns. The grid is all about the width of these columns. If you use percentages you can create a liquid layout. If you use ems you can create a fixed width layout which can resize quite nicely. The approach is to setup a large number of SASS mixins. This is based on the code in Blueprint. The innovation is to not let any of the blueprint class styles get into your code. Instead we use the SASS mixins to apply the code to our semantic css styles. Some examples

In blueprint html ends up like

<div id=wrap class="span-8"> ...

With sass its just

<div id=wrap> ...

but in structure.sass we have

#wrap
  +span-8

this includes the sass mixin +span-8 into the css for #wrap.

This pretty much gives us the best of both worlds - a powerful grid and semantic html source. We also end up with less junk in our css as only the sass mixins that are used end up in the final stylesheets.

Typography

Typography uses one stylesheet (typography.css). It is mostly concerned about getting vertical rhythm in our document. Here we define a desired default line-height in pixels and then use a combination of SASS arithmetic and constants to apply this line height to our typographical styles which are em based. This allows us to create styles with different font sizes that all line up.

Appearance

This is controlled by screen.sass and is all about defining the colour, position and maybe horizontal margins of elements.

New Rails Project (part 2) - Plugins

Posted by Andrew Premdas Fri, 11 Jul 2008 19:19:32 GMT

Now we have a deployed application we can add some plugins to get those extra bits of functionality we want.

Missing Directories

What we've done so far has created a rails project that is to minimal. Applying git and uploading the project has removed any empty directories. If you get errors just create the directories. e.g.

mkdir -p vendor/plugins

Installing plugins on GIT branches

Might be a good idea to install plugins on branches. With sufficient git-fu we should be able to remove plugins later if we really wanted to. This could be a good tip for experimenting with plugins. So for each plugin do

git branch plugin_name
git checkout plugin_name
git add .
git commit -m "installed plugin_name"
git checkout master
git merge plugin_name

Haml and Sass

Haml and Sass are no brainers for me. There are alternatives, but everything I've done with Haml and Sass has pleased me

Assuming you've installed the haml gem, at the root of your project run

 haml --rails .

Testing Framework

Here things get a little more difficult. Basically I'd like to use the full RSpec stack with plain text user stories, but it just seems to be too hard. Also my current user doesn't seem that interested. Really finding that learning curve for RSpec is so steep that I end up not testing.

An alternative is "shoulda". This builds on top of rails in built tests instead of replacing them. Its been suggested that its a gentle way to get into BDD. Anyhow I am tempted by it.

script/plugin install git://github.com/thoughtbot/shoulda.git

Attachments

So far I've used attachment_fu and been fine with it. However there is an alternative called paperclip by the same people who have done shoulda. This seems simpler to use and gets mucho praise in the blogsphere.

script/plugin install git://github.com/thoughtbot/paperclip.git

Tagging

So far have used acts_as_taggable_on_steroids however a newer plugin acts_as_taggable_on exists which supports multiple tag sets. This means that on my list of products I could have a :category, :location tags etc.. This extra functionality might be useful.

script/plugin install git://github.com/mbleigh/acts-as-taggable-on.git

Creating a New Rails Project

Posted by Andrew Premdas Fri, 11 Jul 2008 15:10:45 GMT

A step by step guide to creating a new rails project. The project will be called np. We start with ...

rails np cd np

Setup GIT

git init

Remove log files

We want the log folder to be empty

rm -f log/*.log

Stop Git From Ignoring Empty Folders

We want git to check in all empty folders so we keep the project structure and don't get missing folder errors later. Unfortunately the only way we can do this is put a hidden file in each folder. We use a .gitignore file for this, and the following command puts one in each empty folder

find . ( -type d -empty ) -and ( -not -regex ./.git.* ) -exec touch {}/.gitignore \;

found that my blog is not showing the backslashes which are escaping each bracket in the above command, so try this one instead which doesn't use the brackets

find . -type d -empty -and -not -regex ./.git.* -exec touch {}/.gitignore \;

Remove database.yml and make a template

mv config/database.yml config/database.yml.example

Make Initial Commit

git add .
git commit -a -m "initial commit"

Setup .gitignore

Because we now have no empty folders we can do this before the initial commit

mate .gitignore

Set contents to be

log/*.log
tmp/*
public/cache/**/*
doc/api
doc/app
config/database.yml
vendor/plugins/doc/**/*

Commit changes

ga .
gca

Test Clone

cd ..
git clone --bare np np.git
mv np np.old
git clone np.git
cd np
rake -T
script/console   # wil generate error about database.yml

Move Clone to Git Server

cd ..
scp -r np.git deploy@little-un:/srv/git/

Change Ownership of Clone on Server

sshlun
sudo chown -R git:git /srv/git/np.git

Make Local Clone From Server

rm -rf np
git clone git@little-un:/srv/git/np.git

Setup Database

Each development environment will have its own database settings, and our production environments will in turn have their own secure settings. So we don't want to put database settings in our repository. We can put a template in our repository to guide setup.

git mv config/database.yml config/database.yml.example
git commit -a -m "removed database.yml from repo - added template"

Now each time you clone the repository you will have to setup an appropriate database.yml. Git will ignore this file because you told it to in '.gitignore'.

TIP Keep a local database.yml file on your development box that is configured for your local database settings. Use this as your template.

Capify and Setup Staging (Early Production) Environment

Doing this really early because I think its really important to do as early as possible. Really like to be able to push with git and then deploy.

capify .

Now you need to create a deploy.rb file. I already have one for my production environment, so its just a question of modifying it for this application.

We must modify

  • the application name (must not contain spaces)
  • the repository location

We can then check it by

cap deploy:check

This should product a couple of errors one telling you to run cap:deploy:setup. Make sure you get this (you don't want to overwrite an existing production app). Now setup and check again

cap deploy:setup
cap deploy:check

Now we should be ready for our first deployment. Be aware thought that we have to setup our web server before things will work. Also don't forget to commit changes to repo

ga .
gca -m "capified project and completed deploy:setup"

Web Server Setup

On web server ...

Again copying an existing setting. I'm using Apache and Passenger on Ubuntu. Existing sites are in /etc/apache2/sites-available. Create a new site by copying existing one and modifying. My new one came out as

<VirtualHost *>
        ServerName tc2.little-un
        ServerAlias tc2.andrew.premdas.org
        ServerAdmin webmaster@localhost

        DocumentRoot /srv/rails-apps/tc2/current/public
</VirtualHost>

Then as root

a2ensite tc2
apache2ctl configtest

n.b. should get warning about public folder not existing

Cap Cold Deploy

Back on dev box ...

Now may have done enough to do a cold deploy - which is a first deploy that does some additional stuff

cap deploy:cold

Got error that database table did not exist, so created on server

Errors and Rails Version

Didn't have Rails 2.1 on my server when I did this. Can either freeze rails in application or update server. I'm updating the server for now! Probably should freeze.

Cap Deploy

Have to do at least one cap deploy to get my production database.yml setup (which is done by the capfile)

Just about done - got working production application. Now can get started with plugins and migrations

Getting a Rails action to return to where it was called from

Posted by Andrew Premdas Fri, 04 Jul 2008 15:16:15 GMT

Often in Rails you will want to use a partial in more than one place. Such partials might add or delete things. Once this is done you will want to return to where you were. The following works without javascript and Ajax ...

The information we want is called the HTTP_REFERER. This is contained within the request object which is hugely complex. The request contains an env hash and the HTTP_REFERER is in there.

request.env["HTTP_REFERER"]

Now you can use this in your controller code e.g.

respond_to do |format|
  format.html { redirect_to request.env["HTTP_REFERER"]} 
end

Rails Debugging

Posted by Andrew Premdas Thu, 03 Jul 2008 11:35:02 GMT

Easy peasy once you know how.

  1. start up your server with the -u
  2. put debugger in your code where you want the debugger to start
  3. run that code e.g. in a web browser

The web browser will hang, and a debugging session will be started in the terminal you ran the server. Main things to remember are

  • h get help
  • l list the code where you are
  • reload if debugger doesn't pick up changes in your code give it a little kick
  • cont carry on execution

That should be enough to keep me happy

Older posts: 1 2