Recent News

Counting in CSS

One of the best things you can do as a Rails developer is remember to utilize everything at your disposal. Last week, I had this front-end task to set up dynamic footnotes; I initially assumed I would be doing this in Ruby, until i found this choice CSS2 “counter” support:

body { counter-reset: footnote; }
.footnote:before {
  content: counter(footnote);    
  counter-increment: footnote 1;  
}

No kidding! It’s a good reminder—CSS is quite evolved and mature, and it contains a lot of little-discussed functionality. Remember to exploit it as much as possible (IE6 notwithstanding)…

Take control of your server configuration with Capistrano

A typical Rails deployment involves configuring a number of services via configuration files. Common examples include httpd.conf, nginx.conf, memcached.conf, monitrc, my.cnf, haproxy.conf, et al. These little files are the laces that hold your app together; the tiniest mistake or misconfiguration will usually take your whole operation down. On top of this, if you’ve got multiple servers, you’ve got to make sure that every server is configured correctly.

So why don’t we put these under version control, and then use Capistrano to deploy configuration changes to one or more servers? Here’s one way to do it.

screenshot of a Rails app containing server config files First, config files go in config/server.

In this example, the target servers are running Debian (Etch), and config/server/ corresponds to the root directory of the server—so we’ve got /var, /etc, and so on.

With this under version control along with the rest of the app, you can now roll back to earlier “known-good” configurations lickety-split.

As an added benefit, this increases transparency for your team, since developers can see how the deployment works without having to actually visit the servers.

And here’s where it gets even better—you can now use Capistrano to deploy configs!

Dig on this:

rake deploy:config
desc "Deploy server configurations" 
  task :config,:roles=>:app do
    # Export to a temp directory, to avoid uploading .svn directories.
    temp_dir = "/tmp/capistrano-#{Time.now.strftime("%Y%m%d%H%M%S")}" 
    system "svn export config/server #{temp_dir}" 
    system "scp -r #{temp_dir}/* #{user}@#{host}:/" 
    system "rm -rf #{temp_dir}" 
    sudo "chmod 700 /etc/monitrc" 
    sudo "chmod 600 /etc/mysql/my.cnf" 
    sudo "chmod -R a+wx /var/service/*" 
    sudo "chmod +x /home/deploy/backup_db" 
    deploy::reload_monit
    deploy::restart_mysql
    deploy::restart_mongrels
    deploy::restart_apache
  end
  • This happens to be a subversion environment; if you’re on git you can probably just omit the exporting step.
  • Make sure you completely understand how “scp” works—if this is new to you, bone up, because a mistake here can really ruin your day.

Please note that this code snippet will almost certainly not work for you as-is; you will have to adjust, rewrite, and optimize this for your unique situation.

One last tip: If you run into problems at first, make sure that permissions are reset correctly; these are idiosyncratic and tend to get wrecked in transition. It’s a simple/best practice to explicitly reset the permissions in your deployment.

You’ll thank yourself later—enjoy!

An SSH one-liner to authorize via public-key

Here's a two-part tip on SSH productivity--you can use public-key authentication and SSH's built-in configuration options to save some time every day.

1) Authorize your public key. If you're like me, it's a bother to remember each little step -- here's the one-liner I use for convenience.


  > ssh someuser@remotehost.com "echo `cat ~/.ssh/id_rsa.pub` >> ~/.ssh/authorized_keys" 

This will append your key to the remote host's list of authorized keys.

Don't have a public key yet? You can generate one with:


 > ssh-keygen 

You'll find a brand-new keypair in your ~/.ssh directory. Read up on public-key cryptography if it's new to you.

2) Now add the remote host to your (local) .ssh/config file:

1
2
3
Host rh
  Hostname remotehost.com
  User someuser

The SSH config file can contain many entries; just add this to the list. "Host" is an alias/nickname/shortcut of your choosing.

So, you can now SSH to your remote host with:


 > ssh rh

This will save you a little typing. Public-key authentication is a "best practice" anyway -- it's good to develop the habit. For example, this is the only way to SSH into Amazon EC2 instances, and for administrators, it means you can share access to a SSH account (say, a deployer) without floating the password around.

Bonus tip: If you find Capistrano and Net::SSH behaving quirkily, make sure you have the latest versions of both. Recent updates to Net::SSH have included various updates and fixes relevant to public-key authentication.

cf. http://net-ssh.rubyforge.org/
cf. http://groups.google.com/group/capistrano/

MicroApps (or little ditties) with Sinatra

Me and one of the other horses left the stables recently and went to RailsConf. Of all the sessions I attended, my favorite one was by far Erik Kastner’s talk entitled MicroApps for Fun and Profit.

Erik Kastner explained that MicroApps are small apps that you can write the bulk of the code in a day… or get completely done in one sitting (one day).

They can be simply HTML or HTML/CSS/JavaScript… they can be written in Camping, they can be API mashups, you could use Yahoo! Pipes, it could be just text on a page. You could use Ruby on Rails, you can use a blog engine… it doesn’t really matter, it just has to be done in one sitting.

The app he demoed (called Jeff4Good ) is a one-page web form that takes “donations” of stuff or money to help his friend Jeff who needed money for a hospital trip that cost him a bunch of money.

The Jeff4Good app uses the relatively new ruby microframework, Sinatra. He wrote it within one day. Personally, I have ideas for web apps all the time – it’s rare that I have time to actually get something out there, but the MicroApp “philosopy” that Erik Kastner proposes (along with things like the Sinatra framework) makes it seem so much more possible to get stuff out there. I love the idea of getting something completely done in one sitting – I’ve got waaaay too many ideas that haven’t been implemented right now.

Erik pointed out that the title of the talk should be “MicroApps for fun and Micro Profit” because most of the MicroApps that he has written were not profitable – or if they were, the profit wasn’t much.

The profit that you do gain, however, is that you get to learn something new and you build your portfolio. You can play around with ActiveRecord or DataMapper in new ways. You can start hacking on API’s that you haven’t played with before. You also get to build your portfolio of successful web apps. That can lead to promotions or job offers.

Erik also pointed out that he’s been able to work with some high profile developers and designers because he didn’t need a big commitment from them… you might be able to get a great designer to help out on a fun little project and make your MicroApp look super sweet.

Some examples of MicroApps:

metaatem.com/words (Spell your name in pictures from Flickr)

Twistori (twitter mashup)

Foamee (twitter mashup – tracks who you owe beer or coffee to)

CrocSpotting (a phoblog (photo blog) that uses Yahoo! Pipes & a Flickr feed of Crocs (you know those shoe things))

Learn more about the Sinatra Microframework at sinatrarb.com and gittr.com

Write your first “hello world” Sinatra app in less than 60 seconds:


$sudo gem install sinatra
Then, start writing your code in a *.rb file (e.g. frank.rb).
1
2
3
4
5
6
require 'rubygems'
require 'sinatra'

get '/' do
"OMG, like, hey world!"
end

Save your 5 lines of code and then run the app:


$ruby frank.rb

Then, it should say:


frank takes the stage on port 4567

Go to localhost:4567 in your browser.

“OMG, like, hey world!”

See – fun… and easy!

Less work, more be-ing with quick shell aliasing

This weekend, after working an endless 5 hour work week, I decided that I want to implement new ways for me to continue to be even lazier than I already am…

After laboriously lifting my heavy 4” long fingers to ssh into another server that I couldn’t remember the IP address for, I started to think there has to be a better way.

Why am I always repeatedly type long lines of ssh logins, rake tasks, etc. into the command line? I’m always trying to stay DRY in my application code, and it’s got me thinking, how can I sort of stay “DRY” at the command line and limit the amount of work that I do?

Why don’t I create time saving aliases more often?

One big reason that I don’t create time saving aliases more often is because it’s not brain-dead-easy enough for me to edit my .bash_profile… so, I created an alias to quickly edit my .bash_profile:

# 'be' (for "bash edit")
  alias be='mate ~/.bash_profile'
The really sweet version that re-sources your .bash_profile after you save your changes is:
alias be='mate -w ~/.bash_profile;source ~/.bash_profile'

Then, I decided to take a look at where I could reduce repetitive tasks, so I executed the history command to see what are some of the longer commands that I’ve written repetitively.

~ $ history
   10  ssh deploy@myserver.railsmachina.com
   13  cd Projects2/
   55  rake db:migrate
   57  rake db:migrate RAILS_ENV=test
   88  rake ultrasphinx:bootstrap

I see that I’m typing a lot of long rake tasks like rake db:migrate, rake ultrasphinx:bootstrap, cd Projects/post_it, cd Projects/my_project

So, I’m going to add those…
alias rdb='rake db:migrate'
alias rub='rake ultrasphinx:bootstrap'
alias my_project='cd Projects/my_project/trunk/'
I don’t want to go crazy in one day and add EVERYTHING, I’d rather fine tune this over time and make the process of adding and editing my bash_profile easier… So, by just adding the be alias, I now have an easier way to create shortcuts and it makes me a much happier programmer:
alias be='mate ~/.bash_profile'

We discussed the possibility of writing a function (let’s call it balias) that could automatically add an alias to your bash_profile (e.g. balias myserver "ssh live@8.23.456.78"). My only hesitation with doing that is it could make your .bash_profile a disorganized mess… But, it would be very nice to just add new aliases via command line.

The other challenge is how do you remember all these shortcuts? Type alias in your command line to remember what aliases you have added.
~ $ alias
alias be='mate -w ~/.bash_profile;source ~/.bash_profile'
alias ett='mate app config lib db public test vendor/plugins &'
alias gd='git diff | mate'
alias app_live_1='ssh live@8.22.345.67'
alias app_live_2='ssh live@8.22.345.99'
alias app_live_db='ssh live@8.22.345.222'
alias app_sandbox='ssh sandbox@8.22.43.243'
alias app_staging='ssh staging@8.22.43.244'
alias rdb='rake db:migrate'
alias rdbt='rake db:migrate RAILS_ENV=test'
alias td='mate ~/Documents/todo.txt'
Footnotes:
  • See other people’s .bash_profiles here: http://dotfiles.org/
  • You can also edit your .ssh/config, but I find it just as good to put them in the .bash_profile.
  • You can set up autocomplete for ssh as well – using this Life changing shell function, I’m probably missing something about setting up .ssh/config, but right now, it’s not working well for me since all my logins are always ssh username@8.34.56.123 and not simply ssh domain_name.

Interceptor Methods

Let's say we have a class in a plugin or module somewhere, and we want to override one of its methods to handle more cases, without losing the original functionality. For example, maybe we've got a login module that checks for the user record in a database. We want to make it check an LDAP first, then check the database if the user is not found in the LDAP. Using an "interceptor" pattern can help here. We'll alias the original method, storing a copy of it under a new name. Then we redefine the method to handle the new feature and conditionally call the old method. Here's an example:
    class Unicorn
      attr_accessor :climate

      def frolic
        puts 'Frolic in a meadow, enchant other forest creatures with majesty'
      end
    end
    # this class definition is locked away somewheres

    # now let's reopen the class and add the interceptor
    class Unicorn
      # copy the original method so we can still call it
      alias_method :old_frolic, :frolic 
      
      # let's intercept calls to frolic method
      def frolic
        if @climate == 'tundra' # new functionality
          puts 'Frolic on a glittering glacier, under the Aurora Borealis'
        else # conditionally default to old method definition
          old_frolic
        end
      end
    end

cementhorses.com

Categories

Cement Horses Pics

Archives