Releasing Textilize gem for Rails3 without C extensions

      Rails 3.X doesn't have the textilize and textilize_without_paragraph helper methods. Textilize is a gem brings back the missing method for Rails 3, and it includes the library RedCloth 3.0.4, which doesn't need to be compiled on server. Btw, The newest RedCloth is currently at 4.X though, it requires compiling C extension.


      The reason we need this gem is that we use :textilize at a few places in our apps, and we don't need super fast RedCloth, we just need a working version that don't force us to install C extensions on various production servers. This could be useful for bundle-package usage, where you can rely on the bundle/cache gems.

Related Links: 



Posted by Mysen 06 Jul 2012 at 04:51AM

Deploying Rails apps on CentOS SELinux

In the course of our work we have come across a variety to linux flavors; RedHat Enterprise Linux, Ubuntu, and CentOS seem to be the most common. Lately I had to get a new CentOS box set up with a typical Rails stack, ruby, rvm, Passenger, mysql and so on.

There are plenty of articles that describe how to install the stack, and since the commands change constantly I won't bother with rehashing this. What I want to describe is how to make sure your Passenger app can be run on a locked down SELinux box safely.

The first thing to consider is what SELinux does. It is designed to combine all the best practices on server security and turn them ON by default. In fact, the only port that will respond to traffic is port 22, so that you can ssh in. Everything else is shut down.

Opening the Firewall

So the first thing we need to do is open things up a little bit more, specifically, we'll want to make sure outside people can access our web site, so lets open port 80 for http traffic. On CentOS, the system firewall is handled by the service iptables and configured in the file /etc/sysconfig/iptables. You can enable traffic on port 80 by adding this line to your iptables config file:

-A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT

However, you need to make sure to add this line before any REJECT lines, as the rules are read in order and any REJECT directives will override later ACCEPT directives. Once you have saved the file, you need to restart iptables

$ sudo service iptables restart 

Directory Permissions

Another difference between Ubuntu and CentOS is that CentOS requires that your application directory, and all parent directories, have absolutely the right permissions. To accomplish this without chmod 777 -R * (please don't do that). I like to set up my groups and users carefully. First, off, I have a user that is in charge of logging in and managing the apps. Lets call her releng (release engineer). On the server, I use the /srv dir as it is at root, and has nothing inside. I add an apps dir, then set up my app inside of that, so I have a path like /srv/apps/appsauce (my new app is called appsauce). I then create a symlink ln -s /srv/apps /apps so that in all scripts and config files, I can simply use /apps/appname

Now, we want to make sure releng has access to all these files, so we run chown -R releng /srv. But the apache user needs access to these files as well! So I like to add apache to releng's group: usermod -G releng apache. Now that means we need to make sure the group releng has access to all these files. So we can run: chgrp -R releng /srv. At this point, we have a human user and a process user in the same group, accessing the same directory tree under /srv

Starting Passenger

If you are used to Ubuntu and simply install passenger right away without taking a breath, you probably will run into some trouble. If you check the httpd error logs (/var/log/httpd/error_log) you'll see that passenger is complaining about permissions. It seems that passenger is not allowed to do something it really needs to do. In this case, create files in the tmp directory.

In SELinux, not only are the ports shuttered, but the file permission structure is very strict. The apache user that is running passenger is not allowed to access files or directories it does not create itself, unless specifically given permission at the system level. Giving the apache user this access is a process I won't get into here. Luckily enough, there is a way to create permissions based on how an application is used. This article explains how to properly add permissions for passenger. The idea is to turn off SElinux, run the app, then turn the log of what the app asked for permissions-wise into a permissions policy for that app. Once the correct policy is in place, you can turn SELinux back on and run your app securely.

The article is missing an important piece of information though. If audit2allow has not been installed on your system, you won't find it in the yum repositories. You'll need to install the package policycoreutils-python


At this point, we should be able to run our app with SElinux turned on, and only port 22 and port 80 open for connections. This is a rock solid platform for your product or your clients applications. Leave a comment if you have any improvement suggestions.

Posted by adevadeh 14 Jun 2012 at 08:05AM

Software Engineering Intern - 2012, Kude Labs

This position has been filled. Thanks to all the applicants!

Kude Labs (酷德实验室) is a growing software development firm focused on building high quality web applications. Our office is located in Guangzhou Wuyang New Town (广州市五羊新城).

We are happy to offer internship positions for students looking to improve their skills and gain some practical experience working on real-world projects. Intern positions are part time and can transition into a full time position after graduation. The majority of our full-time employees joined our team first as interns.

1. Software Development Intern- Web Applications, Ruby on Rails

We are looking for smart software engineers with experience and interest in Web applications. We develop in Ruby on Rails with a distributed team partly in China, partly in the US.

Ideal candidates would have:

  • Outstanding analytical thinking and software design skills
  • Computer Science background, or other Engineering degree and significant programming experience
  • Experience with Ruby on Rails, or possibly other Web App framework and ability to learn quickly
  • Experience using Linux or some other flavor of Unix
  • Deep understanding of HTML and CSS
  • Experience with modern Javascript and AJAX techniques
  • Good written and oral communications skills
  • Open-minded and willing to share ideas with others
  • Self-motivated, cheerful, friendly, upbeat outlook

2. Software Testing Intern - Web applications

We are also looking for smart QA engineers for testing the Web Applications we develop.

Ideal candidates would have:

  • Outstanding analytical thinking abilities
  • Patient and precise work style
  • Engineering background
  • Experience with open source tools
  • Some experience using Linux or some other flavor of Unix
  • Excellent written and oral communications skills
  • Self motivated and able to work independently
  • Nonjudgemental, welcoming attitude

To Apply:
Please send an ENGLISH letter of interest, references and resume to:
We look forward to working with you and welcoming you as a part of the Kudelabs family.

Posted by 潘小园 18 Apr 2012 at 05:05AM

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
  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}
      else "Skipping asset pre-compilation because there were no asset changes"

Posted by Shaokun 28 Mar 2012 at 07:11AM

Teatime at Kudelabs

teatime at kudelabs

We just set up a new tea corner to enjoy some winter sunshine.

Posted by adevadeh 12 Jan 2012 at 01:35AM

Looking for an Admin Assistant

We think Kudelabs is a great place to work. Luckily for you, we are looking for someone to join our team. The position available is Administration Assistant. To apply please send your ENGLISH cover letter and resumè to

Task scope:

  • Support and assist in HR, Accounting, and office administration
  • Translating English-Chinese for alien employees/visitors
  • Maintaining office place, organizing accommodation for visitors
  • Assisting with travel arrangements and visa
  • Procuring office supplies and special items
  • Offering support to company events

Education and skills:

  • Major in English, Business Administration, HR related disciplines
  • Good command of English in speaking and writing
  • Proficiency with basic office software
  • Must be a true qi-gong master, able to perform the 42 katas while playing ukulele
  • Smart, independent, and flexible/adaptable
  • Self-motivated, competent with communicating via email


  • Students graduating in 2012 are welcome to apply
  • Be really interested in Office job and accountant business.
  • Local resident is preferable but not a must.


  • Full time
  • Salary will depend on experience and ability (RMB2500-3500)
  • Company lunch provided
  • Flexible working hours

Posted by adevadeh 27 Dec 2011 at 02:41AM

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


When I started to use Git, I felt really pain for it. The problem is that when your team mate told you that he has checked in, and you are willing to see the update right away. So you just 'git up', and then you probably see something like 'you need to commit first before merging'. Oops, but I am just in the middle of modifying something, I am not ready at all to check in.

Well, that's what git up are different from svn up. Here, one tips is:

git stash save   # this will save your local changes to a temporary place, and clean up your workspace
git up                 # here, you could just update to the HEAD of your branch, probably master
git stash pop    # then you could get your local change back, and you probably need to fix the conflicts here

Posted by Shaokun 22 Dec 2011 at 07:49AM



自从@americanfood从夏威夷带了一把ukulele回来,ukulele的发展势头在Kudelabs就一发不可收拾。如果你来到Kudelabs, 也许你第一句话会问,"你们这儿是卖Ukulele的么?",我们也不会感到奇怪,因为确实有人这样问过!而昨天更有6个ukulele到货,上图为Jevgenij与其中一部分小U的合照。

Kudelabs已经无法阻止Ukulele了,地球人已经无法阻止Ukulele了!让ruby 和 ukulele 欢乐地融合起来吧!

Since @americanfood brought a Ukulele back from Hawaii, Kudelabs has been caught up in a Ukulele fever. Visitors to the office sometimes ask if we are a musical instrument company. Yesterday we got another shipment, and now the office really does look like an instrument shop!

We love our ukes! The world can't stop the Uke!

In the photo above, Ukulele learner @jevgz practices his moves. Photo by @littlepxy.

Posted by 潘小园 08 Dec 2011 at 08:25AM

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 -,, 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,]
  • 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