rails 3.2: cap deploy with assets

In rails 3.2, you need to precompile your assets (javascripts, stylesheets & images) when doing your deployment to server. There are couple ways to do this:

Add public/assets into your git branch before deployment.

You need to run the rake assets:precompile task locally, and then commit it into your staging or production branch. Note that you cannot commit into your development branch, otherwise, you have problem in development mode, e.g. javascript function got included twice.

The problem is obvious, you end up with extra files in your git repository, and your staging or production branch cannot be merged back into development branch.

Use Capistrano deploy/assets to precompile automatically on server.

This is quite easy to do. You just need to modify your Capfile:

# Uncomment if you are using Rails' asset pipeline
# load 'deploy/assets'

I use this method if the assets is quite tiny. However, it's not something super smart that will detect if your assets content really changes. It just simple precompile every time when you do cap deploy. So, it your assets is pretty large, your every deployment will be very slow. And if your server is quite cheap, you will notice that the server CPU is very high for a while.

I end up to write a cap task, cap deploy:assets, to do with it.

My idea is we don't deal with any assets precompile if just cap deploy, since it might be quite expensive. We wrote another deploy task deploy:assets for it, similar to the deploy:migrations.

  • first, we precompile locally, to avoid high cpu on server, and I actually found that my MacBook Pro is much powerful than some of our servers.
  • zip the whole public/assets directory as public/assets.tar.gz
  • upload the public/assets.tar.gz to shared directory
  • unzip the assets.tar.gz to shared/assets
  • remove the public/assets & public/assets.tar.gz locally, so that we won't have problem in the development mode below is the task I wrote for this deployment behavior.

namespace :deploy do
  task :ln_assets do
    run <<-CMD
      rm -rf #{latest_release}/public/assets &&
      mkdir -p #{shared_path}/assets &&
      ln -s #{shared_path}/assets #{latest_release}/public/assets

  task :assets do
    run_locally "rake assets:precompile"
    run_locally "cd public; tar -zcvf assets.tar.gz assets"
    top.upload "public/assets.tar.gz", "#{shared_path}", :via => :scp
    run "cd #{shared_path}; tar -zxvf assets.tar.gz"
    run_locally "rm public/assets.tar.gz"
    run_locally "rm -rf public/assets"


Updated: I saw a simple trick to speed up by checking if the assets directories changed or not before doing a assets:precompile task

namespace :deploy do
  # http://stackoverflow.com/questions/9016002/speed-up-assetsprecompile-with-rails-3-1-3-2-capistrano-deployment
  namespace :assets do
    task :precompile, :roles => :web, :except => { :no_release => true } do
      from = source.next_revision(current_revision) rescue nil
      if from.nil? || capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ | wc -l").to_i > 0
        run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile}
        logger.info "Skipping asset pre-compilation because there were no asset changes"

Posted by Shaokun 28 Mar 2012 at 07:11AM

Rails on Campus: 华农版 - Session #3

The excellent students at South China Agriculture University

Rails on Campus Roundup / Rails on Campus 大聚集

Last Saturday we concluded the Rails on Campus: 华农版 (SCAU) program with session #3. We wish to thank Dean Song, Professor Sun, and all the students who took the time to attend. We really appreciate working with such amazing students, and we were very happy to be able to come to your school.

上周六我们在华农顺利地进行了Rails on Campus 第三期活动。在此非常感谢宋主任,孙教授以及所有到场的学生。 真的很难得可以跟这么多这么优秀的学生一起分享和学习, 我们也很高兴能够来到你们学校。

And special congratulations to 欧振聪 Clarence Au (@onionou) the winner of our coding competition!


Over the course of 3 sessions, we've introduced the students to the basics of Rails, and hopefully they will be able to keep learning about Rails and ruby. To recap, here's what we've gone over:


  • Getting the Rails environment - RailsInstaller.org, ruby-lang.org, SublimeText
  • Basic ruby syntax - messages.each {|m| puts m}, hash = {:key1=>'val1'}
  • Creating a new Rails app from scratch - rails new miniblog
  • Using scaffolding to get started quickly - rails generate scaffold message body:text
  • Creating associations between models - message: has_many :replies, reply: belongs_to :message
  • Using Rails view helpers to build forms - form_for [:message, Reply.new]
  • How to access the Rails session - session[:user_id]
  • Writing filters to manage authentication - before_filter :require_login
  • Custom routes for easy URLs - match 'login' => 'sessions#new'
  • Deploy your app to share with the world - heroku, DotCloud

The result of our work in class should be a working miniblog that you can share with your friends. Anyone can login, post messages, and reply to other users' messages.

在课堂上我们的练习任务是:创建一个miniblog, 通过这个miniblog 你可以跟朋友分享,每个人都可以登录, 发表信息同时也可以回复其他用户的信息。

We'd love to see you continue with your code. Add more features, improve the design, and put it up on heroku! Make sure to let us know via the Rails on Campus Weibo account.

我们非常希望你们可以继续写代码,让你的miniblog变得更好。 增加更多的功能,做更好的设计,然后放上heroku! 在微博上@RailsOnCampus 展示你的成果吧!

We also would appreciate any feedback, so please let us know how we can make the event go more smoothly next time, or if there's anything else we should cover. We hope to take this program to other universities in the area, and perhaps come back to SCAU for a second season next year.

欢迎对我们的活动提出您的宝贵意见! 这对我们很重要,希望我们下一次可以组织得更好,活动开展得更顺利。如果你有感兴趣的话题希望我们可以分享,欢迎给我们来信! 我们希望到广州更多的大学去分享,可以的话也希望明年回到华农分享更多有趣的话题!

Session #3 / 第三届

The third session in our program focused on completing the feature set to make our miniblog a full web application. Of course we needed a way for users to log in, so that we know who says what. To that end, we went over how to track user sessions, and how to use before_filters to manage users and make sure they log in when they need to.

在第三期我们会分享一些关于如何给我们的miniblog添加新功能新应用,使其变成一个更加完整的网络应用。 首先,我们必须想个办法让用户可以登录,这样我们才知道谁说了什么。然后我们也分享了如何去追踪用户及其发表的信息,以及如何使用before_filters 去管理用户,让他们在必要时进行登录。


Rails on Campus is a program started by Leon Du and Shaokun Wu, 2 ruby developers in Guangzhou, China. The idea is to build a good set of material for introduction courses that can be used to teach Rails on college campuses. College students are often not exposed to the latest development techniques, and are left to learn on the job. The goal of this program is to introduce students to the world of open source development frameworks to help prepare them for a good job.

Rails on Campus是由中国广州两位Ruby 开发者, Leon Du和伍少坤发起的。活动的初衷是为大学Rails的教学积淀一些有价值的学习材料。大学学生接触新技术的机会不十分多,而常常要上到工作岗位才开始学习。希望通过这次活动,可以为同学们带来更多开源的开发框架,以此为将来的好工作更好地准备自己。

Rails on Campus is sponsored by:

Rails on Campus的赞助团队有:

Posted by adevadeh 08 Dec 2011 at 04:08AM

Rails on Campus: 华农版

Last week we had our first Rails on Campus session at the South China Agriculture University (华南农业大学). We had an excellent turnout of 50 or 60 top-notch students. We were really impressed with their knowledge of web development in general, and their enthusiasm to learn new things.

上周末我们 Rails on Campus的第一次活动在华南农业大学展开了。大家反应热烈,有5,60个学生参加了我们的活动。同学们对知识的渴望给我们留下了深刻的印象,参加的同学基础知识也非常不错。

The first session focused on:


  • Setting up the Rails environment on your computer
  • Learning about the origin of Rails and ruby
  • Creating a new Rails app from the command line and adding a simple scaffold

We built a working web app as a demo in about 10 minutes, starting from rails new and finishing with a nice looking miniblog.

The only problem was the recent issues we've been having accessing rubygems from China. This made it very difficult for the students to get a Rails environment working on their own laptop. We hope to have a good solution for this problem before the next session.

For our next session, we'll continue to build on the same application by adding a reply feature.

Here are the links from session #1



Rails on Campus is a program started by Leon Du and Shaokun Wu, 2 ruby developers in Guangzhou, China. The idea is to build a good set of material for introduction courses that can be used to teach Rails on college campuses. In Guangzhou, and many other areas around the world, college students are often not exposed to newer technology, and are left to learn on the job. The goal of this program is to introduce students to a new world of open source development frameworks that are quite popular around the world. Not just Rails, but also things like Node.js or Python/Django.

Rails on Campus是由中国广州两位Ruby 开发者, Leon Du和Shaokun Wu 发起的。活动的初衷是为大学Rails的教学积淀一些有价值的学习材料。在广州,以及世界的一些其他的城市,大学学生接触新技术的机会不十分多,而常常要上到工作岗位才开始学习。希望通过这次活动,可以为同学们带来更多热门的开源的开发框架,以此为将来的好工作更好地准备自己。不单单是Rails,以后我们可能还会涉及到像 Node.js 或者 Python/Django 这样话题。

Rails on Campus is sponsored by:

Rails on Campus的赞助团队有:

+ gzruby - The Guangzhou Ruby Group http://gzruby.org/list
+ Kudelabs http://kudelabs.com
+ Beansmile http://beansmile.com

Posted by adevadeh 17 Nov 2011 at 03:15AM

how to make CI tool hudson work for rails project on ubuntu

hudson is awesome CI(continuous integration) tool. 

We want to install it on our ubuntu server to do CI for our rails projects.

Here are the steps of how to make it work:

1. ssh username@servername, to login remotely to your ubutu server.

(After you install a brandly new ubuntu on the server, you will need to sudo apt-get install openssh-server, then you can ssh it from your laptop)

2. install hudson on the ubuntu server, here is the instructions:


(the good news after you finished the installing is, hudson is already so system daemon that will be auto-started when ubuntu reboot.)

(after installed hudson and reboot ubuntu server, open a web browser, access http://serveaddress:8080/, you can see the lovely interface of hudson. Then you need to install several plugins for hudson, like ruby, rake, git etc, this can be easily done through hudson UI)

3. install ruby on the ubuntu server, run the following command

sudo apt-get install ruby

(this will install ruby 1.8.7 as default)

4. after login ubuntu server on your laptop, run this command on the terminal of your laptop to act as the hudson user auto-created by the hudson installation.

sudo -Hiu hudson 

(you have to act as hudson user, because the next step is to install rvm, if you install rvm under another account, hudson account will not be able to execute rvm command.)

5. install rvm, here is the instructions:


(make sure you are using hudson account on ubuntu, by this way, the rvm will be installed under hudson directory)

(you will need to create a .bashrc file to $HOME dir, and add a this line to that file

[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function)

5. rvm install ruby-1.9.2

6. rvm --default ruby-1.9.2


then we are almost there!


7. How to set Hudson to use smtp.gmail.com to send emails after a build failed?

go to hudson config page

smtp server: smtp.gmail.com

username: ******

password: *******

usessl, true

smtp port: 465

charset: utf-8



8. I run into another problem when trying to check out a project.

We used "externals" feature in svn 1.6, but when I build a project for the 1st time, the code in external is not checked out.

My solution is in the config screen of the project, at the section setting svn urls, press "add" to add a location.

then fill in the svn url of the external codes,

then fill in correct local directory that the external codes should go in.

then this problem is bypassed. 


9. set the build part in project:

a. select "execute shell"

b.  add the following lines:


# Environment setup

#source "$HOME/.rvm/scripts/rvm"

# Use the correct ruby

rvm use 1.9.2@gemsetname

# Do any setup
# e.g. possibly do 'rake db:migrate db:test:prepare' here
# bundle install
# Finally, run your tests
10. when using emai-ext plugin, the email content should be:
Check console output at $BUILD_URL to view the results.
Below is the raw output:
${BUILD_LOG, maxLines = 100000}

Posted by 张晓峰 01 Jul 2011 at 09:03AM

Rails on Campus Wrap-up

After 2 great sessions of Rails on Campus: 华工版, we'd like to thank everyone who took part in helping to plan and organize this event. We learned a lot from the experience, and we hope the attendees did as well. We plan to take our materials from this first run, refactor, and put on a better program next year!

Before we close out for the year though, I wanted to go over what you can do to continue learning on your own.

Install Rails

http://railsinstaller.org - Download and run the installer. It will install everything you need to get started writing your own Rails apps (ruby, git, rubygems, rails).

Get the demo code

http://github.com/kudelabs/roc-demo2 - Clone the project and get it running on your computer .

git clone git://github.com/kudelabs/roc-demo2.git 
cd roc-demo2
rake db:migrate
rails s
open http://localhost:3000

Write some code

http://notepad-plus-plus.org/ - You can use any text editor to write code, but its much easier in a real code editor like Notepad++. It's free, give it a try.
http://http://guides.rubyonrails.org/getting_started.html - Take a look at the Rails Guides for more in-depth tutorials
http://asciicasts.com - Another great resource with tons of tips and information

Share with the world

http://heroku.com - A free service to host your amazing Rails app! It works right from the command line and in 5 minutes you have a public site that you can show to anyone.

Just Do It

So now you have no excuse. You have the tools, you have the code, you have the servers. Go write an inspiring app and make us proud!

Posted by adevadeh 09 Jun 2011 at 09:24AM

tags in git for sane version numbers

The problem

In the svn days, branching was expensive, repositories were centralized ... life was hard. But one thing was easy; each revision had a number and that number went up each time a change was committed to the repository. This made versioning easy: v1, then v2, later v345, finally v1202, anyone can see this and understand.

When switching to git, there is a bit of a learning curve, as each commit is named with an unpronounceable 40 character hexidecimal hash. It's really easy to tell a client, "I just deployed v434, it has all the features we talked about yesterday" Or, "Yeah, you're looking at v57, the new features are in v62" . Its much more difficult to tell a client, "Sorry for the mixup, you are looking at gdac40b3 but the bug is fixed in 616f65bb". I can already see eyes glazing over in confusion.

git has a really handy tags feature. It is perfect for large complicated projects where several commits go into each new release, and the release schedule is on the scale of weeks rather than days. You tag 1.0, then 1.1, 1.1.1 - and so on. These are sane version numbers and are easy to talk about. The problem is that they take work. When you are working on something uncomplicated and the release cycle measures in days or hours, nothing beats the old commit by commit versioning system.

The solution

To get automatic revision numbers in git, we use the native tags, but in a slightly different way. The git describe, command has a handy feature, it can figure out how many commits your repository has after the last tag. What this means is that when you create a tag, say 1.0, 4 commits later git describe will call this "1.0-4-616f65bb". What I propose is to use this feature to our advantage. Rather than tag at the end of a target version, say 1.1.1, we tag at the beginning, and let git to the work. And rather than 1.1.1, we use a meaningful name. So for example, I might use a tag like this:

$ git tag -a 'milestone1' -m 'starting work for milestone 1, due in 2 weeks'
$ git push --tags

From here on out, git will automatically count the commits for us, so we have a sane version number to talk about with clients. If we want to see it, all we need to do is this:

$ git describe

Which I can then use to tell the client, "Ok, I just deployed milestone1-34, we added the feature to read your thoughts, please check it out and let me know - oh wait ... the software can tell me."

Something that we always do is embed the current revision somewhere into the software so that we know what version the user is seeing. In Rails, I just added this to config/initializers/git_helper.rb

git_version_cmd = "git describe"
$revision = `#{git_version_cmd}`
$revision = $revision.strip
puts "starting version: #{$revision}"

I can now put $revision in the footer, or hide it in a comment somewhere on the page. This helps keep everyone in the loop and prevent misunderstandings about what version someone may be looking at.

This is just one way to manage versions in git, we'd love to hear yours!

Posted by adevadeh 22 Dec 2011 at 07:50AM

Rails on Campus: 华工版 - Session 1

The first Rails on Campus session went very well last saturday, with around 50 budding rubyists in attendance. We went over the history and purpose of Ruby and then Rails, and then did a live demo of: Build your own miniblog in 20 min.

Rails on Campus 上周六的活动开展得非常顺利,大约50名对Ruby感兴趣的同学参加了此次活动。我们对Ruby 和Rails 的历史以及意义都作了简单的阐述,并且现场做了一个迷你演示:怎么样在20分钟内建一个属于你微博。 :)

Since we didn't have wifi at the venue, it was hard to show all the links and make sure students could write them all down, so here's a list of important links:

由于我们现场没有wifi设备,很难向大家展示所有的链接,同时也考虑到可能一些同学也来不及记下来。 大家不妨看看以下关键的链接,可以更好地理解我们分享的内容:

Thanks to everyone involved, and to all the attendees. We all look forward to working together again next week!


Posted by adevadeh 09 May 2011 at 11:05AM

functional tests with machinist and authlogic

Authlogic and Machinist are two libraries that are a great help in getting a Rails app up and running quickly. But once we had a prototype running, and some solid unit tests going, I ran into a snag. How do I create Users and UserSessions in a way that agrees with AuthLogic so that my requires_user before filter is working properly within a functional test?

Posted by adevadeh 18 Aug 2009 at 01:05AM

Rails 2.2 has been released

The much anticipated Rails 2.2 release is finalized with a host of new features. One of the features we are most excited about are the new multi-threaded capabilities for Rails. This will improve application response time in general, and allow us to get more use out of each server. I think memoization can be useful as well, it will be interesting to see how much it helps. As usual, Peter Cooper at Ruby Inside has put together an all-encompassing post with all the info you might need. And as a side note, this release also includes a little patch submitted by our team.

Thanks and congratulations to the core team for another solid release.

Posted by adevadeh 27 Nov 2008 at 07:06PM

mongrel --prefix does not properly notify rails 2.1.1

As of Rails 2.1.1, ActionController::AbstractRequest.relative_url_root no longer exists. It has been replaced by ActionController::Base.relative_url_root. This allows you to run your rails app in a virtual sub-directory of your webserver. The mongrel rails handler uses this method to set the relative url for your rails app. When working properly, mongrel_rails start --prefix /app would result in rails automatically generating URLs like http://somedomain/app/action.

Currently in mongrel 1.1.5 and Rails 2.1.1, if you wish to have this functionality you must set the relative_url_root by hand somewhere in your environment like so:
<pre> ActionController::Base.relative_url_root = "/app" if 'production' == ENV['RAILS_ENV'] </pre>

I have submitted a patch to mongrel, but if you can’t wait for the new release of mongrel, here is the patch:
<pre> Index: lib/mongrel/rails.rb =================================================================== --- lib/mongrel/rails.rb (revision 1036) +++ lib/mongrel/rails.rb (working copy) @@ -147,9 +147,15 @@ require env_location require 'dispatcher' require 'mongrel/rails' - - ActionController::AbstractRequest.relative_url_root = ops[:prefix] if ops[:prefix] - + + if ops[:prefix] + if ActionController::Base.respond_to?('relative_url_root=') + ActionController::Base.relative_url_root = ops[:prefix] # new way to set the relative URL in Rails 2.1.1 + else + ActionController::AbstractRequest.relative_url_root = ops[:prefix] + end + end + @rails_handler = RailsHandler.new(ops[:docroot], ops[:mime]) end

Posted by adevadeh 09 Oct 2008 at 07:52PM