Nathalie’s (now my fiancee) temporary position has ended last week, and she is looking for a new position in or around Bristol.
Currently working in marketing/web marketing, it’s not the best season/time to search for a new position.
With an average of 1 new job per day, I don’t think she’ll find something quickly.

I’d say that it’s normally a bad news, but this time it might be better than we thought.

Since her graduation, Nathalie always wanted to work in the web industry, That why we created SerialCooking and she was pretty good at managing the blog and the community on this project, but it was missing something: Coding.

She is now learning XHTML/CSS and web standard  to have a better understanding of the whole process. And I must admit she is doing very well, and likes coding. Will she be looking for a Junior Web Developer position soon? Never know ;) .

She has a good understanding of technologies, web technologies and social networking.

So if you know someone who know someone with a job opportunity (Every position considered!), please let her know. Thanks a lot.

Here Nathalie Derain, online marketing executive resume in pdf.

Loosing data can be quite ... annoying.

Loosing data can be quite … annoying. (Photo on Flickr)

The last thing you want is to have a disaster on your server and being unable to recover your data.
I run all my projects and different blogs on one server, hosted by OVH. So I have multiple databases, gems, websites and configurations that I want to backup.
Hopefully, OVH provide with every dedicated server an external FTP server dedicated to backups.
So I’ve installed backup-manager and make it runs twice a day.

Warning

Because backup-manager compress your files into archives, it will cost you some space on the disk, so be sure to change the default value of the target and do your backup on a proper partition.
If you don’t, backup-manager will do the backups in / by default, so when it’ll be full, your sever will not work properly.

Installation

sudo apt-get install backup-manager

Tweacking

Installation create a default config file. You’ll need to edit it to match you configuration.

sudo vi /etc/backup-manager.conf

Before I explain you my config file, here is how I’ve config my server:

  1. I have 4 PHP Applications (Blogs/apps) and 3 Ruby on Rails apps running on it.
  2. Each application has it own directory in /home/ .
  3. REE is installed in /opt, and so are the gems.
  4. I keep an automatic backup of my server configurations (DNS/Host/Users/Right…) in /home/config (Only accessible by root).
  5. I’ve created an new partitions call “/backups”.

So basically, want I want is:

Save my /home/*, /etc/*, /opt/*, all my databases to an external partition then an external FTP.

In backup-manager.conf, you’ll need to set:

Local Storage

  • BM_REPOSITORY_ROOT “/backups” Where to store local backups
  • BM_ARCHIVE_TTL “3″ Local archive time to live
  • BM_ARCHIVE_METHOD “tarball” Which archive method do you want to use (You can mix and match different types)

Backup directories

  • BM_TARBALL_DIRECTORIES “/etc /home /opt” Directories to backup.
  • BM_TARBALL_BLACKLIST “/home/nobackup” Exclude some directories

Backup transfer

  • BM_UPLOAD_METHOD “ftp” Backups transfer method
  • BM_UPLOAD_FTP_USER “myftpusername” FTP login
  • BM_UPLOAD_FTP_PASSWORD “myFtpPassw0rd” FTP Password
  • BM_UPLOAD_FTP_HOSTS “ftp.backups.com” FTP Server
  • BM_UPLOAD_FTP_PURGE “true” Clear the remote directory before to upload
  • BM_UPLOAD_FTP_DESTINATION “/” Upload existing directory.

Incremental Archives (set BM_ARCHIVE_METHOD = tarball-incremental)

  • BM_TARBALLINC_MASTERDATETYPE “monthly” Complete archive creation frequency (daily or monthly)
  • BM_TARBALLINC_MASTERDATEVALUE “23″ Creation day of the complete archive

Mysql databases

  • BM_MYSQL_DATABASES “mysql1 db2 db3″”_ALL_” mysql db names separate by space or _ALL_
  • BM_MYSQL_ADMINLOGIN “backupuser” Mysql user (DO NOT USE ROOT!, see below)
  • BM_MYSQL_ADMINPASS “backuppassword” Mysql user password
  • BM_MYSQL_HOST “localhost” Mysql Server
  • BM_MYSQL_PORT “3306″ Mysql port
  • BM_MYSQL_FILETYPE “bzip2″ Backup compression method

Others

  • BM_PRE_BACKUP_COMMAND “” Execute a command before the backup
  • BM_POST_BACKUP_COMMAND “” Execute a command after the backup

BM_MYSQL_DATABASES

Please be careful, as you’ll need to write in this file the login and password of a user to procede to dabases backups.
Don’t use root!, neither an existing user. You’re going to create a new user, with limited right on databases and tables, and you’ll protect the backup manager config file.

mysql -u root -p
GRANT SHOW DATABASES,SELECT,LOCK TABLES ON *.* TO 'backupuser'@'localhost' IDENTIFIED BY 'secretpassword';
exit;
sudo chown root:root /etc/backup-manager.conf
sudo chmod 640 /etc/backup-manager.conf

Now you can set the 2 values in the backup-manager config file.

export BM_MYSQL_ADMINLOGIN=”backupuser”
export BM_MYSQL_ADMINPASS=”secretpassword”

BM_MYSQL_FILETYPE

Mysql database compression after dump.

export BM_MYSQL_FILETYPE=”bzip2″

Make sure that bzip2 is intalled

sudo apt-get install bzip2

BM_POST_BACKUP_COMMAND

Execute a command once bakcup done. You can,for example, use this to send an email after the backup.

Automated backups

You can use cron to schedule your backups. Before just create a little script

cat << <acronym title="End of file">EOF</acronym> > /etc/backup-manager.sh && chmod 700 /etc/backup-manager.sh
#!/bin/sh
test -x /usr/sbin/backup-manager || exit 0
/usr/sbin/backup-manager
<acronym title="End of file">EOF</acronym>

And now you can add this script to your contab

crontab -e

And add

1 0 * * * /etc/backup-manager.sh

Here is ubuntu cron doc, easy to understand (https://help.ubuntu.com/community/CronHowto)

Do more

For example, you can call backup-manager with backup-manager -c /path/to/configfile and by this way, having 2 crons. One running every days, executing backups of files and db, and another one, in the middle of the day, only for the db ;) .

You can do much more than these options (cd/dvd burning for example), please be sure you read the complete wiki at http://wiki.backup-manager.org/index.php/Main_Page#Documentation

My moo business cards set

This year I’m looking to more networking and freelancing in the Uk, so I’ve made these business cards and they’ve been printed by Moo.

As alway, Moo quality is just fantastic, and I’m happy with the result. But I’ll certainly do another with Web Strategy Developer or something like that (more generic than Ruby on Rails evangelist).

Anyway, what do you think?

business card

Let’s go cycling … and taste a car!

Accidented bike #6

6 months ago, I decided to change my commute habits, to become greener. My bike became my principal mode of transport. And it’s really pleasant. Even in winter, you fell alive, you arrive earlier to work and at home, your not stuck in traffic. Honestly I didn’t see any inconvenient. Well, I didn’t.

I’d already realized that, sometimes, car drivers doesn’t care about cyclists. They pass us very close, they use cycle lanes or cycle part at red lights. Anyway, not really a big deal, but sometimes it can be more dangerous.

Last Friday (29th of June), a car driver simply didn’t see me, and cut my road. I hit the car back, and fall down.

First, a teenager helps me to stand up, and took my bike to the pavement, the driver took nearly 2 or 3 minutes to came out of her car. When see came out, the first think she said was : “Do you have a mobile phone to call someone?”. Well, under the shock and the pain, I said yes, and took my phone to call my fiancée 3 times. She didn’t respond (hopefully). I tried to move my right shoulder, and completely felt down under the pain. So I asked the driver to call an ambulance or the police. After going to her car taking her phone, she just asked me to call again my fiancée. Nathalie wasn’t here, so she didn’t respond. So the driver just propose me to give me a lift to the hospital (Why bloody why didn’t she wants to call someone).

She wasn’t really in panic, but I don’t know were she had her license. On the way to the hospital, she passes 2 red lights!!!.

She stopped nearly 200 meters before the hospital entrance, and said “I’ll leave you here”. The emergency room is completely the opposite!. I took her phone number, after asking 2 or 3 times, and before she left, I took a reg number.

At the BRI (Bristol Royal Infirmary), I had a very nice doctor, she took care of me, did everything. The results, right collar bone broken, tendons stretched, I’ll not be able to use my arm for 4 weeks as minimum, and really pissed off about the driver attitude.

Since we are in Bristol, it’s my second accident. Last tme we were waiting to cross a road, and hit by a drunk driver in St Augustine Parade.

I think, next time, I’ll probably remove my French flag above my head ;) .

So last we I didn’t code at all, I’ll try to do small things this week, but it’s really hard with one hand :( .

Anyway, please, if one day you have an accident, please, take time with the victim, and be human !.

So that’s it, you want to start development with Ruby on Rails, but you don’t know where to start.
The good thing is Ruby on Rails has a very clever and smart community, and you can find lots of documentation on the web.
Here is quick summary on where to start.

Books

If you really want to learn Ruby on Rails, the best first thing to do is certainly to invest in a good paper/electronic book.
There are lots of books available outside but I would only recommend two of them.

Agile web development with Rails
Probably the most popular book outside. The third version include Rails 2.x support and was co-written by Sam Ruby, Dave Thomas, David Heinemeier Hansson, et al.
A must have.

The Rails Way
Obie Fernandez came here with one of the best book for rails developer. From the beginning to Rspec, you’ll learn how to start coding and testing your new Rails App. Btw, Obie Fernandez is the guy behind Thoughtbot.

Wiki

New ruby on rails wiki
While your waiting your book to be delivered, you might have a look to the  new ruby on rails wiki started by the Rails Activist Team. Let say, in a nutshell, that this wiki is a big FAQ for Rails, and beginners should find here responses to their questions.

On line Documentation

Rails Guides
You know what they say, RTFM before asking a dummy question! So be sure to checkout the awesome Rails Guides before asking any question, you’ll certainly find your answer.

Official Ruby on Rails doc
Well, not the best looking, but at least it does the job.

Rails Brain
Rails brain ajaxified the official ruby doc, for a smoother search experience. The good thing is you can access on line, old Rails versions doc. Note there is also RubyBrain

Rails Searchable API Doc
A very nice Ajax interface to parse the Rails (and some other gems) api. You can download it, and copy the directory in your web server root directory to have an off line access to it.

ApiDock
Probably Certainly the best documentation search tool ever!. It combines documentation and community in the same project. Very smart. (Note there are Firefox and Textmate extensions).

Community

Rails forum
A friendly and smart community, alway here to help. Feel free to ask your question if you didn’t find the answer above.

Ruby on Rails Google group
I’m not a big fan of malling lists/Google groups, but it’s a nice one, with -again- a huge community.

Screencast/Podcasts

Definitively one of the best way to learn how to develop is to listen/watch  some else coding.

Railscast
I don’t remember how was my Monday morning before the Railscast. Ryan Bates will offer you every week  a new free screencast, full of good coding practice and advice. A must to watch, with a warm cup of tea.

Peepcode
One of the best quality screencast for Rails/Merb/Development in general. If you are new to rails, I just recommend you the REST for Rails2 screencast and the Rails2 PDF.

Rails Envy Podcast
Still need to present them? Presented by Greg Pollack and Jason Siffier Saffer Seifer (he never knows how to pronounce names either!) . These guys are just crazy, and yes it’s a compliment. Every week, during 20 minutes, you’ll learn all the hot new stuff happening in the Ruby/Rails/Merb community, with fun. Check it out.

What else?

Sure you can extend this list with blog talking about Rails, Twitters of trendy rails developers to follow, github account to watch … sure, but I think with this list above you’ll have a good entry point to the community.
Now have fun and happy coding ;) (go write your tests!).

First time I wanted to use Jquery with Ruby on Rails I had some difficulties understanding how it can works.

Sure, you can easily use Jrails, that’ll brings you RJS helpers with Jquery, but I quite like the unobstrusive way, so Jrails is not (for me) the best solutions.

Let’s code together

What do we want?

We are going to simulate a blog post comment system. We need to be able to list the comments/create a new comment/rate a comment/delete a comment.

All this need to work with and without JavaScript enabled.

I deliberately didn’t use any user/role filtering, the goal of the code is to show of to work with Rails and Jquery

Step1: Prepare the app

We want to work with Jquery, so we don’t need the Prototype files anymore. Just remove everything from your public/javascript/ appart application.js.

In your master layout add this bunch of lines

        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
        <% if protect_against_forgery? %>
          <script type='text/javascript'>
              //<![CDATA[
                window._auth_token_name = "#{request_forgery_protection_token}";
                window._auth_token = "#{form_authenticity_token}";
            //]]>
            </script>
        <% end %>
        <%= javascript_include_tag 'application' %>

We are linking Jquery to the google hosted version, and calling the application.js and setting the forgery protection.

Then in your application.js copy and past the content of my default application.js (Also available as a gist)

jQuery.ajaxSetup({ 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")} })

function _ajax_request(url, data, callback, type, method) {
    if (jQuery.isFunction(data)) {
        callback = data;
        data = {};
    }
    return jQuery.ajax({
        type: method,
        url: url,
        data: data,
        success: callback,
        dataType: type
        });
}

jQuery.extend({
    put: function(url, data, callback, type) {
        return _ajax_request(url, data, callback, type, 'PUT');
    },
    delete_: function(url, data, callback, type) {
        return _ajax_request(url, data, callback, type, 'DELETE');
    }
});

jQuery.fn.submitWithAjax = function() {
  this.unbind('submit', false);
  this.submit(function() {
    $.post(this.action, $(this).serialize(), null, "script");
    return false;
  })

  return this;
};

//Send data via get if JS enabled
jQuery.fn.getWithAjax = function() {
  this.unbind('click', false);
  this.click(function() {
    $.get($(this).attr("href"), $(this).serialize(), null, "script");
    return false;
  })
  return this;
};

//Send data via Post if JS enabled
jQuery.fn.postWithAjax = function() {
  this.unbind('click', false);
  this.click(function() {
    $.post($(this).attr("href"), $(this).serialize(), null, "script");
    return false;
  })
  return this;
};

jQuery.fn.putWithAjax = function() {
  this.unbind('click', false);
  this.click(function() {
    $.put($(this).attr("href"), $(this).serialize(), null, "script");
    return false;
  })
  return this;
};

jQuery.fn.deleteWithAjax = function() {
  this.removeAttr('onclick');
  this.unbind('click', false);
  this.click(function() {
    $.delete_($(this).attr("href"), $(this).serialize(), null, "script");
    return false;
  })
  return this;
};

//This will "ajaxify" the links
function ajaxLinks(){
    $('.ajaxForm').submitWithAjax();
    $('a.get').getWithAjax();
    $('a.post').postWithAjax();
    $('a.put').putWithAjax();
    $('a.delete').deleteWithAjax();
}

$(document).ready(function() {

// All non-GET requests will add the authenticity token
  // if not already present in the data packet
 $(document).ajaxSend(function(event, request, settings) {
       if (typeof(window.AUTH_TOKEN) == "undefined") return;
       // IE6 fix for http://dev.jquery.com/ticket/3155
       if (settings.type == 'GET' || settings.type == 'get') return;

       settings.data = settings.data || "";
       settings.data += (settings.data ? "&" : "") + "authenticity_token=" + encodeURIComponent(window.AUTH_TOKEN);
     });

  ajaxLinks();
});

This is my default application.js when I want to work with Jquery.

Basically what brings you these functions are :

Any link for a class get/post/put/delete will be called via ajax only if JavaScript enabled. Same for form with ajaxForm class.

The code

You can find the original code on my github at

http://github.com/spyou/railsjquery/tree/master

I’ve created a comment resource. The comments table has a body and a score field.

Here is the comments_controller.rb

class CommentsController < ApplicationController
  #This is a virtual comment manager. There is no user detection, no session
  before_filter :load_post

  #This is our entry point, I'm just going to display a factice post to comment
  def index
    @comments = Comment.all
    respond_to do |format|
      format.html #we only respond to the html request
    end
  end

  def new
    @comment = Comment.new
    if !request.xhr?
      @comments = Comment.all
    end

    respond_to do |format|
      format.html
      format.js {render :layout => false}
    end
  end

  def create
    @comment = Comment.create(params[:comment])
    respond_to do |format|
      format.html { redirect_to comments_path() }
      format.js {render :layout => false}
    end
  end

  #This is not a "normal" update, I'll use this one to add points to the comment
  def update
    @comment = Comment.find(params[:id])
    @comment.score = @comment.score + 1
    @comment.save

    respond_to do |format|
      format.html { redirect_to comments_path }
      format.js {render :layout => false}
    end
  end

  def destroy
    @comment = Comment.find(params[:id])
    @comment.destroy

    respond_to do |format|
      format.html { redirect_to comments_path }
      format.js {render :layout => false}
    end
  end

  protected

  def load_post
   @post = "This is a factice post, I hope you like it. Just comment on the bottom!"
  end
end

As you can see on it, we handle 2 different types of responses

    respond_to do |format|
      format.html
      format.js {render :layout => false}
    end

Format.html will load your [actionName].html.erb, but the format.js will load a page called [actionName].js.erb were you can put all the callback javascript you need.

For example here is my index.html.erb

    <%=
        #Use a helper to display the current comments of the post
        comments_display(@comments)
    %>
<div class="newComment">
    <%= link_to 'Create a new comment', new_comment_path(),:class => "get"%>
</div>

and the _comment.html.erb

<div id="comment<%= comment.id %>">
<%=
    content_tag(:p,
    comment.body)
%>
<!-- We are accessing the update function so we use put as class -->
<span class="score"><%= comment.score %></span><span> - <%= link_to 'Add one point!',comment_path(comment),:class => "put"  %></span>
<p> - <%= link_to '*Delete this comment',comment_path(comment),:method => :delete,:class => "delete"  %></p>
<p><%= comment.created_at %></p>
<hr />
</div>

You can see the use of get/put/delete class.

Here is now the new.js.erb (Where I call a _form.html.erb to render the new comment form)

$(".newComment").html("<%= escape_javascript(render :partial => 'form') %>");
ajaxLinks();

And here is the update.js.erb (Where I’m suppose to update the score of the comment without refresh)

//Update the score
$('#comment<%= @comment.id %> span.score').html("<%= @comment.score %>");

The tests

Well, the problem with the test is, you can test the rendering of you page (in plain text) but you can’t be sure of the javascript execution.

I’m made some simple tests (testing the plain text) that you can find in the test/functional folder.

(Example with the new comment method)

#Testing the comment creation
  context "handle :create" do
    context "by html" do
        setup do
           post :create, :comment => { :body => "My comment" }
        end
          should_change "Comment.count", :by => 1
          should_redirect_to("the index"){comments_path()}
      end
      context "by xhr" do
        setup do
           xhr :post, :create, :comment => { :body => "My xhr comment" }
        end
          should_change "Comment.count", :by => 1

          should "Display the new comment link" do
            assert_match(/new comment/,@response.body)
          end

          should "display the created new created message" do
            assert_match(%(My xhr comment),@response.body)
          end

      end
  end

This is just the beginning, I’m now looking to some Javascript testing solution for Rails, will be part of another tutorial.

In a nutshell

So in a nutshell, what’d learn here is :

  • Rails + Jquery is easy
  • format.js + file.js.erb and you’r done
  • A good application.js can save your ass

Just checkout the complete source code

git clone git@github.com:spyou/railsjquery.git
rake gems:install
rake db:create


jquery-rails-tutorial_1242648062355

I hope it was useful.

mysocialdecklogo

After having released www.serialcooking.com, I needed to do something just for me (I work on serialcooking with Nathalie).

This monday, I started a web implementation of Tweetdeck, and even if it’s now finished now, it goes very quickly.

I’ve used twitter_auth, and worked on it only 2 nights currently, but I want to realease it as soon as possible (Before the end of may?).

Here is a screeshot of the actual work

mysocialdeck

So far, I’ve got the account creation working, the search, the column saving. I’ll work this week end on the group impletation and attack the facebook auth and status display next week.

You can already register to mysocialdeck.com, to be sure to have your token for the beta.

Mysocialdeck.com is going to be develop with Rails 2.32, HAML, Twitter_auth and Jquery. I’m still looking for the best javascript testing solution. The rest of the test are going to be done with shoulda and factory-girl.

What do you think of the idea? the logo? I’d really like to heard about you.

It was the big things weeks ago, but I didn’t had time to test it. Twitter_auth, allows you to user the twitter authentication on you application. And it’s really sweet!.
Let’s do a small implementation together.

Step 1: Prepare your development box

Because Twitter doesn’t allow the callback parameter anymore, you’ll need to setup your workstation.
I recommend to install passenger in your development box, and use the hosts file to manage your different applications.

For that, just follow the official passenger doc. Easy peasy.

Then you’ll need to prepare your localhost. I like to work with [applicationName].local.

sudo nano /etc/hosts

Then add an extra line

127.0.0.1    twitterauth.local

Now create your rails app

rails -d mysql twitterauth

or take my source code my github twitterauth-test ;)

Finally add the site to apache

sudo nano /etc/apache2/sites-enabled/twitterauth

Then copy (and modify) these lines on it

<VirtualHost *:80>
ServerName twitterauth.local
DocumentRoot "/home/[REPLACE WITH YOU PATH]/twitterauth/public"
RailsEnv development
RailsAllowModRewrite off
<directory "/home/[REPLACE WITH YOU PATH]/twitterauth/public">
Order allow,deny
Allow from all
</directory>
</VirtualHost>

Restart apache

sudo /etc/init.d/apache2 restart

You now have your development box working with passenger. Next application you’ll develop, just add a new line in the /etc/hosts file, a new site-enabled file restart apache and you’re ready.

Step 2: Install twitter_auth as a depency

Modify you environement.rb by adding

config.gem 'twitter-auth', :lib => 'twitter_auth'

Then sudo rake gems:install, and you’ll have the gem installed.

Step 3: Prepare the application

script/generate twitter_auth
rake db:create
rake db:migrate
touch tmp/restart.txt

In order to work properly, your app (even on development mode) need to be registered on twitter. Visit Twitter apps and form with your informations.

Twitter doesn’t accept the callback param anyone, so you’ll need to provide http://twitterauth.local/oauth_callback as a callback in the configuration form.

twitterauth_config_twiiter

When you save the informations, Twitter will give you 2 keys that need to be copied in config/twitter_auth.yml.

then

touch tmp/restart.txt

Your app is now ready!

Step 4: Let’s do some code

We are going to create a twitter controller, with an index action

./script/generate controller Twitter index

Twitter_auth use the REST twitter api style, so to the loggued user friend time line copy and paste this in twitter_controller.rb, and returns a Json array. (visit the twitter api wiki for more informations)

Before calling functions that need you to be logged in, you’ll have to use the login_required method on before_filter.

This is going to be our root method so add in routes.rb


map.root :controller => "twitter"

This code goes into twitter_controller.rb

before_filter :login_required
#Retreive the friend timeline
def index
@tweets = current_user.twitter.get('/statuses/friends_timeline')
logger.info @tweets
end

Then in your views/twitter/index.html.rb

<ul class="tweets">
<% @tweets.each do |tweet| %>
<li><%= link_to(tweet['user']['screen_name'] + ':', 'http://twitter.com/' + tweet['user']['screen_name'], :target => '_blank') + tweet['text'] %></li>
<% end -%></ul>

After a bit of CSS, if you open http://twitterauth.local you should have something like this

twitter_1242116387102

twitterauth

Today I’ve played with twitter_auth, and I must admit it’s really sweet.

As I leave for a camping trip this afternoon, I’ll not be able to write a tutorial on how to setup you development box, but I’ll do it on Monday.

You can just check my source code on github. (You’ll need to add the database.yml and the twitter_auth.yml before it works).

Have a nice week end! I’m of for the downhouse farm now.

This morning I needed to transform  some Textmate snippets to Gedit format.

I’ve wrote a quick and dirty code for that (tmsnippets2gedit on github)

You just need to copy the script to the textmate bumdle root directory, and run it.

You’ll have a new file call result.xml that you need to edit to specify the language format (JS,Ruby,XSL, …).

Then rename it and copy it to your gedit snippets folder.

The code is not pretty, and is certainly perfectible, but for the moment it works. I’ll to combine it to the tm2gtksw2 project (this one convert Texmate styles to Gedit styles)

Ruby on rails

Recommend Me