I just compiled a page with links to Rails 3 tutorials, screencasts, talks, articles & blog posts. It’s not a long list yet but I’ll be maintaining the page religiously as we move towards a Rails 3 public release. Please email me if you put together something relating to Rails 3. I’ll add it to add to the list.

{ 0 comments }

via: Joseph Wilk » Cucumber waves goodbye to GivenScenario.

Did you know you can reuse steps definitions inside step definitions? Here’s what I mean.

Let’s say you’re writing a scenario for Logout and it looks something like this:

Scenario: Logout
  Given I am logged in
  When I follow "Logout"
  Then I should see "Logout successful!"
  And I should get a success response

Let’s assumed that before this scenario, you wrote a scenario for logging in like this:

Scenario: Login with email
  Given I am not logged in
  And user "melvin@volcanicmarketing.com" with password "secret" and openid " " exists
  When I go to the login page
  And I fill in "email" with "melvin@volcanicmarketing.com"
  And I fill in "password" with "secret"
  And I press "Login"
  Then I should see "Login successful!"
  And I should get a success response

Now inside the step definitions for the “I am logged in” (from the Logout scenario), you could run through the process of logging in manually or you could reuse a lot of the step definitions you’ve already written for the “Login with email” scenario.

Here’s how you do it:

# features/step_definitions/auth_steps.rb

Given /^I am logged in$/ do
  Given 'I am not logged in'
  And 'user "melvin@volcanicmarketing.com" with password "secret" and openid " " exists'
  And 'I go to the login page'
  And 'I fill in "email" with "melvin@volcanicmarketing.com"'
  And 'I fill in "password" with "secret"'
  And 'I press "Login"'
end

As you can see, you just have to include the step inside single quotes. Pretty cool, huh?

PS: I am a cucumber beginner so don’t take anything in this post to be the right way to do things.

{ 1 comment }

Javascript in Haml

by Melvin Ram

One thing that is not obvious with HAML is how to add javascript. In the past, haml didn’t really like javascript that much but the latest version of haml on github makes it very simple. It’s done using the :javascript filter. Here’s an example:

:javascript
  jQuery(function(){
    tog("#forgot_password_clicker", "#login_form");
    tog("#forgot_password_clicker", "#forgot_form", forgot_text);
  });

You can also mix in ruby variables by using the standard way of interpolating ruby with strings through: #{ }. Here’s an example of how it all works in a full page with a ruby variable mixed in:

!!! XML
!!!
%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}
  %head
    %meta{'http-equiv' => "content-type", :content => "text/html;charset=UTF-8"}

  %body
    - @some_ruby_variable = "something goes here."
    :javascript
      #{@some_ruby_variable}
      jQuery(function(){
        tog("#forgot_password_clicker", "#login_form");
        tog("#forgot_password_clicker", "#forgot_form", forgot_text);
      });

This makes this HTML:

<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
  <head>
    <meta content='text/html;charset=UTF-8' http-equiv='content-type' />
  </head>
  <body>
    <script type='text/javascript'>
      //<![CDATA[
        something goes here.
        jQuery(function(){
          tog("#forgot_password_clicker", "#login_form");
          tog("#forgot_password_clicker", "#forgot_form", forgot_text);
        });
      //]]>
    </script>
  </body>
</html>

{ 1 comment }

Git Workflow

by Melvin Ram

creative-flow-directly-from-god1

ReinH | A Git Workflow for Agile Teams

Sharing of good work-flow is one of the keys to adoption and effective use of new technology.

Git is a relatively new technology and it’s workflow is not a topic that is discussed often in the Rails community SO it intrigued me when Bryan Liles mentioned the above article by ReinH in one of his videos. I highly recommend giving it a read as it presents some interesting ideas.

Here’s an example. Recently I had a need to build an ecommerce site. Spree is a nice open source ecommerce system built on Rails… however, it does not suit my needs perfectly and when I started looking around the code, I found some code that could be refactored to act more effectively.

I like to commit often… sometimes a little too often. Sometimes I’ll make a change, commit it, do a browser check to see if it works, go back, fix any errors, commit again, and repeat the cycle. The result of my frequent committing is that I have a ton of tiny commits that others won’t really find useful following along. If they tried, they’d understand, but they’d waste a ton of time because the commits are small and often filled with errors that are fixed on the next 2 or 3 commits.

What should I do? The article by ReinH proposes an answer to the problem. Go check it out! Be sure to not be a passive blog reader. Please leave feedback on what you thought. It acts as fuel for bloggers.

{ 1 comment }

Freeze Rails

by Melvin Ram

When developing a rails app, it’s a good idea to “freeze” your app. What this means is that you’re making a copy of rails in your RAILS_APP_ROOT/vendors/rails directory. This will help reduce your dependencies… just in case you deploy your app to a machine that does not have the version of Rails you used to develop it (older or newer.)

This article covers the topic really well: Softies on Rails: Freezing Your Rails Application.

One thing it doesn’t cover is how to freeze a specific version of rails. It’s pretty simple:

rake rails:freeze:gems VERSION=2.1.0

This will allow you to run your app against the version of rails your app was written for.

{ 2 comments }

James Britt wrote up a blog post talking about his experience with HAML, the alternative to ERB. His basic position (from what I gathered) was that it’s for noobies and that no one has explained to him why or how HAML makes real world code better… either than saying “wait, it’ll start looking beautiful soon enough and you won’t go back.”  This is my detailed, somewhat-reasoned response.

I like HAML because it’s clean and easy to read. Cleaner & easier to read than ERb… and yes, I’ll back that up with code:

http://pastie.org/private/n8ipfrkxlremo4jwtxiww

Converting the ERB file to HAML took less than 4 minutes, mostly hitting the delete key.

A 39 line code becomes 31 lines… and that’s not even the big win. Now if you don’t think the HAML code chuck is visually easier to digest than the ERB version, that’s fine. Stay with ERB.

I find HAML code is easier to maintain & write… and it has nothing to do with a lack of knowledge of html or anything else.

How is it easier to write and maintain?

First, there is the overt clarity when it comes to sass (css) & haml code.

## haml file
.container
  .header
    %h1 Site Name
    %ul
      %li= link_to ...
      %li= link_to ...
      %li= link_to ...
  .content
    stuff
  .footer
## sass (css) file for this

.container
  background-color: black

  .header
    background-color: white

    h1
      font-family: Funky
      font-size: 3em
    ul
      li
        a:link, a:visited
        a:hover
  .content
  .footer

Do you see the pairing? I LOVE that! I find it clean & easy to read.

Secondly, it’s very ruby like.

This:

<% if @subscription.state == 'trial' %>
  <label>Trial expiration date:</label>
  <%= @subscription.next_renewal_at.to_s(:long_day) %>

<% else %>
  <% if @subscription.amount > 0 %>
    <label>Next charge date:</label>
    <%= @subscription.next_renewal_at.to_s(:long_day) %>
    <br/>
    <label>Next charge amount:</label>
    <%= number_to_currency @subscription.amount %>
    <br/>
    <label>Current payment method:</label>
    <%= @subscription.paypal? ? 'PayPal' : "#{@subscription.card_number} / #{@subscription.card_expiration}" %>
  <% end %>
<% end %>

becomes:

- if @subscription.state == 'trial'
  %label Trial expiration date:
  = @subscription.next_renewal_at.to_s(:long_day)

- else
  - if @subscription.amount > 0
    %label Next charge date:
    = @subscription.next_renewal_at.to_s(:long_day)
    %br/
    %label Next charge amount:
    = number_to_currency @subscription.amount
    %br/
    %label Current payment method:
    = @subscription.paypal? ? 'PayPal' : "#{@subscription.card_number} / #{@subscription.card_expiration}"

Which looks & feels more like ruby? For me, the choice is clearly the second one. It literally removes anything that doesn’t communicate what the code should do.

Anyway, to each his own.

{ 6 comments }

Something interesting I discovered today while working on an email is the ljust & rjust methods (think left & right justified) for Ruby strings. What it does is it makes sure that your string has at least a certain number of characters and if it doesn’t it adds some characters. Here’s a small code snippet from the rdocs that is pretty self explaining:

"hello".ljust(4)            #=> "hello"
"hello".ljust(20)           #=> "hello               "
"hello".ljust(20, '1234')   #=> "hello123412341234123"
"hello".rjust(4)            #=> "hello"
"hello".rjust(20)           #=> "               hello"
"hello".rjust(20, '1234')   #=> "123412341234123hello"

This is useful when sending emails with Rails that are plain text emails. It can help you align things that look like columns, like this:

INVOICE
----------------------------------------------------------

Bill to:
<%= @account.user.name %>

Description                                          Price
----------------------------------------------------------
<%= (@product.name).ljust(36) %> <%= number_to_currency(@product.amount).rjust(21) %>

If you have any questions about this invoice, please contact
<%= AppConfig['from_email'] %>.

Thank you for your business!

This would produce an email that might look like this:

INVOICE
----------------------------------------------------------

Bill to:
Michael Jordan

Description                                          Price
----------------------------------------------------------
Nike Air shoes                                        $150

If you have any questions about this invoice, please contact
support@nike.com

Thank you for your business!

{ 0 comments }

Moonshine is an amazing new rails plugin by Rails Machine. It configures your server, gets it ready for your app by installing the necessary gems & native packages and deploys your app. Built on top of Capistrano & Puppet, it really takes most of the pain out of deployment.

In this blog post, I’m going to walk you through how to use Moonshine to go from a fresh installation of Ubuntu server 8.10 to being live with your app. So let’s get going:

NOTE: Support this blog by subscribing to the RSS Feed. It’s free.

Step 1. Initial server setup

You’ll need an Ubuntu box to get started. After the basic install you’ll need to run a few commands to get the box ready.

Log into your server via ssh & change your root password

ssh root@123.123.123.123
passwd

Change 123.123.123.123 with the IP of your server everywhere you see it.

Add a new user called rails and give it a password

adduser rails

Give it sudo permissions

visudo

And add this below “root ALL=(ALL) ALL

rails   ALL=(ALL) ALL

On your local machine:

ls ~/.ssh/

If it shows you id_rsa.pub, skip this next step (which generates the ssh):

ssh-keygen

Next, we’re going to copy your public key to your server so you can securely connect to it without having to enter your password. Again on your local machine, run:

scp ~/.ssh/id_rsa.pub rails@123.123.123.123:/home/rails/

Now on your server, run this:

mkdir /home/rails/.ssh
mv /home/rails/id_rsa.pub /home/rails/.ssh/authorized_keys
chown -R rails:rails /home/rails/.ssh
chmod 700 /home/rails/.ssh
chmod 600 /home/rails/.ssh/authorized_keys

It’s a good practice to change the SSH port for your machine so that’s what we’re going to do next:

nano /etc/ssh/sshd_config

Change “Port 22” to “Port 2222” or a different number

Save your file and close it (Ctrl+X, then Y and finally press enter-key)

Okay, now it’s time to setup IP Table Rules.

nano /etc/iptables.test.rules

In this file, enter your iptable rules. Here’s a decent I got fromhttp://articles.slicehost.com/assets/2007/9/4/iptables.txt. IPTables are like your firewall so all info is provided without warrantee. It’s your responsibility to use it wisely.

*filter

#  Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT -i ! lo -d 127.0.0.0/8 -j REJECT

#  Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

#  Allows all outbound traffic
#  You can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

#  Allows SSH connections
#
# THE -dport NUMBER IS THE SAME ONE YOU SET UP IN THE SSHD_CONFIG FILE
#
-A INPUT -p tcp -m state --state NEW --dport 2222 -j ACCEPT

# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT

Save that file and close it. Then run this:

iptables-restore < /etc/iptables.test.rules
iptables-save > /etc/iptables.up.rules

Now to make this info stay when you restart the server, run:

nano /etc/network/interfaces

And enter a line below the “iface lo inet loopback” line, as shown below:

  ...
  auto lo
  iface lo inet loopback
  pre-up iptables-restore < /etc/iptables.up.rules

  # The primary network interface
  ...

Save & close that file and then run:

  /etc/init.d/ssh reload

Now it’s time to do some stuff on your local machine to make it easy to connect with your server.

On your local machine, open ~/.ssh/config file with textmate or your fav text editor:

mate ~/.ssh/config

and add your info using the template below:

Host blackbox
Hostname 123.123.123.123
User rails
Port 2222

Don’t forget to change your port number & IP as well as pick a name for your server that makes sense.

Save & close that file. Now you should be able to connect to your server by just typing:

ssh blackbox

Okay, we’ve got one final thing we need to get your initial server setup. That’s getting your server access to your github account (which you don’t need but most people have it so you should probably get one, even if it’s just to contribute to open source stuff.)

Once you’ve ssh’d into your server using the above command, generate your ssh key similar to how to you did it on your local machine:

ssh-keygen

It will ask you if you want to give it a password. I usually don’t give it one and I don’t know if that’s a good/bad thing. In anycase, when you’re done, you want to output the public key it generates by running this:

cat /home/rails/.ssh/id_rsa.pub

Copy the key that is outputted and enter it into your github account which you can usually do at:https://github.com/account

Alright, you’ve now completed step 1, which was getting the initial server ready.

Step 2 – Adding moonshine to your project & configuring it.

In this step, you’ll add the moonshine plugin to your project & configure it properly so it knows what you want it to do on your server.

On your local machine, go to your rails project directory and add the plugin:

ruby script/plugin install git://github.com/railsmachine/moonshine.git

Add all the gems your project needs to your environment.rb file.

Next, run the moonshine generator to create the necessary files:

ruby script/generate moonshine

This should make an output like this:

  After the Moonshine generator finishes don't forget to:

  - Edit config/moonshine.yml
  Use this file to manage configuration related to deploying and running the app:
  domain name, git repos, package dependencies for gems, and more.

  - Edit app/manifests/application_manifest.rb
  Use this to manage the configuration of everything else on the server:
  define the server 'stack', cron jobs, mail aliases, configuration files

        create  app/manifests
        create  app/manifests/templates
        create  app/manifests/application_manifest.rb
        exists  app/manifests/templates
        create  app/manifests/templates/README
        exists  config
        create  config/moonshine.yml
        create  config/gems.yml

As the output suggests, the next thing you should do is edit config/moonshine.yml

Edit config/moonshine.yml

First give your app a name (such as your_app_name), pick where the files of your app will reside (by setting deploy_to) & tell moonshine where to grab your application from (by setting repository)

  :application: your_app_name
  :deploy_to: /srv/your_app_name
  :repository: git@github.com:username/your_app_name.git

Next, if your app has directories in the public directory that need to stay persistent, uncomment this:

:app_symlinks:
  - uploads

If you don’t, the files will be removed every time you deploy since it gets the files from your git repo and it won’t be there.

You’ll also probably want to uncomment the local_config section, which will upload your local copy of /config/database.yml to the server, while bypassing your git repo.

:local_config:
  - config/database.yml

You probably want to leave the next section (:shared_children:) alone. It basically keeps everything the same.

Now save your file and from your terminal/command-line, run this command to generate a /config/gems.yml file, which will contain a list of gems that your app needs (based on what you specified in config/environment.rb)

rake moonshine:gems

Like the comments say, if your gems depend on native packages, you need to specify it next with :apt_gems. For example:

:apt_gems:
  :paperclip:
    - imagemagick

Next, change Passenger & MySQL settings to suit your app & hardware. For example, on a 256MB ram box, you might lower the max_pool_size to 2 or increase it to 8 for 1GB ram server.

Finally, if your app uses SSL, you’ll need to set your ssl properties with something like this:

:ssl:
  :ip:
  :certificate_file:
  :certificate_key_file:
  :certificate_chain_file:
  :vhost_extra:
  :only:

Set the :only: to true if your entire site should be ssl protected. If you are self-signing, can you can use:self_signed: true like this:

:ssl:
  :self_signed: true

When all is done, you might have a file that looks like this:

  :ruby: ree
  :application: yourapp
  :user: rails
  :group: rails
  :ssl:
    :self_signed: true
  :deploy_to: /srv/yourapp
  :domain: yourapp.com
  :repository: git@github.com:username/reponame.git
  :app_symlinks:
    - assets
  :local_config:
    - config/database.yml
  :shared_children:
  - system
  - log
  - pids
  - config
  :apt_gems:
    :paperclip:
      - imagemagick
  :passenger:
    :max_pool_size: 3
    :use_global_queue: true
  :mysql:
    :innodb_buffer_pool_size: 128M

Edit app/manifests/application_manifest.rb

In the application_manifest.rb, you’ll specify a few things:

  1. Which recipe(s) you want to use
  2. Packages you haven’t already specified
  3. Any rake commands you want run the first time

Recipes

The file that is generated uses the default_stack recipe. What this means is it will install Apache, Passenger, MySQL, Rails, NTP, Cron & Postfix. Checkout vendor/plugins/moonshine/lib/moonshine/manifest/rails.rb to see the actual method. For many apps, the default will work fine.

TODO: Add instructions for what to have in place of the default_stack if I want to use sqlite as my database (if my app is really small).

Additional Packages

If your app needs to have a package installed that hasn’t been specified yet, this is the place to add it. For example, if your app uses BackgroundRB, you’d specify it here.

TODO: Add example of how backgroundrb might be installed.

Run rake commands

You might need to run a rake command after your app has been deployed to initial things. This might be the place to add it.

TODO: Add example. Something I might want to do is do a mysql dump before I move forward… but this is just hypothetical.

Capify your project

Once you’ve got your app configured, capify your app by running the following code while inside your rails app directory:

capify .

Now open config/deploy.rb and replace it’s content with this:

server "blackbox", :app, :web, :db, :primary => true

Replace blackbox with the name you give your server in your ~/.ssh/config file.Next, store the files to your repo and push it to your git repo:

git add . && git commit -am "added moonshine" && git push

Step 3 – Deploy

Once all the configuration is done, you’ll see all your hard work pay off.

First thing you’ll do is setup the server. From your rails app root, run this:

cap deploy:setup

Once that is done, run this:

cap deploy

At this point, you should be done and your app should be live.

Step 3.5 – Add SSL

If your site uses SSL, this next section will get you setup with it. After you’ve deployed your app with the self-signed method as described above, ssh into your server and generate a new certificate request:

ssh blackbox
sudo openssl req -new > mynewsite.csr

It will ask you to fill in a bunch of info that will need to match the info you provide your SSL provider (such as GoDaddy). The key one that you’ll want to pay attention to is Common Name. That needs to be your domain name (without the https://). For my app, i didn’t include the www and I’m not sure if that makes a difference. Next lets move these to a better location:

mkdir /home/rails/certs
mv mynewsite.csr /home/rails/certs/mynewsite.csr
mv privkey.pem /home/rails/certs/privkey.pem

Once done, output your certificate request by doing this:

cd /home/rails/certs/
cat mynewsite.csr

Copy that and enter it when your SSL provider asks for it.

Once your SSL provider approves your SSL, they’ll provide you with two files. One will be the certificate file and the second will be the certificate chain file. For godaddy, they provide a zip file that contains two files: yourdomain.com.crt & gd_bundle.crt. Save these two files in a directory called certs on your local machine. Change into that directory and copy the files to your server by running this on your local machine:

scp * blackbox:/home/rails/certs/

This should copy the files to /home/rails/certs/ on your server.

The final step is to update config/moonshine.yml, commit it to the git repo and deploy again. Open up config/moonshine.yml and replace:

  :ssl:
    :self_signed: true

with

:ssl:
  :ip: 123.123.123.123
  :certificate_file: /home/rails/certs/yourdomain.com.crt
  :certificate_key_file: /home/rails/certs/privkey.pem
  :certificate_chain_file: /home/rails/certs/gd_bundle.crt

Save & close this file. Next update your git repo.

git add config/moonshine.yml
git commit -m "Updated moonshine config file with SSL info"
git push

Now it’s time to deploy but we have one more tiny step. When you were creating the certificate request, it asked you to enter a password in. Apache will ask for that password every single time it wants to restart and moonshine won’t be able to enter this in for you. So we’re going to remove that password from the private key. (for more info) So log into your server & remove it by doing:

ssh blackbox
cd certs
cp privkey.pem privkey.pem.bak
openssl rsa -in privkey.pem.bak -out privkey.pem

This will ask you to enter your password that you entered while generating the certificate request. When you’re done, you’re ready to deploy again:

cap deploy

That’s it! You should be good to go now. And if you’re in the market for managed hosting, particularly for your Rails apps, definitely check out RailsMachine, creators of moonshine!

PS: I originally wrote this guide as part of the moonshine wiki. Feel free to head out there and add to it. It’ll help everyone involved.

{ 16 comments }

jQuery is an alternative to Prototype, which is the default javascript library inside Rails. Since RJS generates javascript based on prototype, you might think you can’t use jQuery in it.  Although it’s technically true, you can still use jQuery by using the page.call feature of RJS. Here’s an example:

## test.js

$(function(){
  ...
};

function do_something_amazing {
  ... some slick jQuery code ...
};

## something.rjs called using link_to_remote or form_for_remote:

page.call 'do_something_amazing'

Gotcha

A simple gotcha is if you include “function be_amazing {…};” inside the “$(function(){…};”  you’ll get an undefined error.

Credits: I came across this approach while helping shipstar in the #rubyonrails IRC channel

UPDATE: Using RJS isn’t the best approach if you value unobtrusiveness. Here’s a copy/paste of some reasons why “RJS is evil”.

dfr|work: it’s directly coupled to your dom but isn’t in it.
dfr|work: i mean, what’s rjs? it’s just a callback thing. Just specify it when you’re making ajax request.
dfr|work: and if you need the data from server, specify it via json. It’s clean and simple.

Expect a follow-up to this explaining how to do this the right way.

{ 0 comments }

[Link] Ruby Basics

by Melvin Ram

Peter Cooper posted a new blog entry that links to 17 Videos Covering Basic Ruby Techniques. These videos cover the basics and may not have any surprising new info but it’s nice to review the basics from time to time. Take a look.

{ 0 comments }