Everybody around me is using Dropbox these days. I love Dropbox a lot, and I got one tip to share, today. I use Dropbox as my Git repository l hosting and use it to work on my own projects. The main reason is because I am too lazy and I don’t want to carry laptop.
This is how I do it:
- Initialize a project locally with Git
- Use command line and go to your local Dropbox directory
- Git clone from your local project repository
- Delete your local project repository
- Git clone from your Dropbox directory
The reason I don’t initialize project with Dropbox directory is because I want to save some Dropbox space. Because once you initialize a project, you will always want to ignore some files and if you clone it from your local directory then you will get a clean copy of source repository.
Once you setup these things, then you can basically checkout and project code from a machine that installed Dropbox. Easy! Right?
I hope GFW will allow my brothers and sisters in China using Dropbox soon so they can enjoy using a lot of benefits like this.
Everybody knows Rails migration is awesome. It is known as a very successful pattern, and I really like it. But today I have a weird requirement which is I need to frequently drop and create table schema while testing one part of my SF Muni Tracker application, and it has nothing related to Rails. Besides I’m a super lazy developer, so I really want to have something like the Rails migration rake task, then I decided to see how Rails does it and if I can reuse some part of its code.
Basically, the database.rake file contains all the db migration magics an related classes are ActiveRecord::Base, ActiveRecord::Migration and ActiveRecord::Migrator.
The main part of db:create looks like this:
task :all => :load_config do
ActiveRecord::Base.configurations.each_value do |config|
local_database?(config) do
create_database(config)
end
end
end
create_database is a long method, but I can write something simple using ActiveRecord::Base to replace it, I have attached my code at the end of this blog.
The main part of db:drop looks like this:
task :all => :load_config do
ActiveRecord::Base.configurations.each_value do |config|
next unless config['database']
local_database?(config) do
drop_database(config)
end
end
end
Similar to create_database, I can write my own drop_database method.
db:migrate looks like this:
task :migrate => :environment do
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
So all of them are not difficult, I just need to mock database configuration and reuse some ActiveRecord methods, so I implemented the following Rakefile, I used PostgreSql as an example:
require 'rubygems'
require 'rake'
namespace :db do
DB_CONFIG = { 'development' => {
'database' => 'sample',
'adapter' => 'postgresql',
'username' => 'phoenix',
'password' => '',
'host' => 'localhost',
'port' => '5432'}
}
task :load_config do
require 'active_record'
ActiveRecord::Base.configurations = DB_CONFIG
end
task :drop => :load_config do
ActiveRecord::Base.configurations.each_value { |config| drop_database(config) }
end
task :create => :load_config do
ActiveRecord::Base.configurations.each_value { |config| create_database(config) }
end
task :migrate => :load_config do
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations.values.first)
ActiveRecord::Base.logger = OpenStruct.new(:info => nil)
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
end
end
def drop_database(config)
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
ActiveRecord::Base.connection.drop_database config['database']
end
def create_database(config)
encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => encoding))
ActiveRecord::Base.establish_connection(config)
end
I believe those code maybe even simpler if you use Sqlite3. The tricky thing is, you need to mock ActiveRecord::Base.logger ,manually specify database connection info. After that you just need to create db/migrate/ directory and put all your migration files within it. You can create your own generator if you want to generate the migration, but I don’t really need it, rails_generator directory is the right place to take a look if you want to create the generator. So that’s it! Isn’t it simple?
这篇博客来分享下,最近一次我对自己网站的小重构。
Rails里推荐的一种验证方式,是在ApplicationController 中创建一个authorized?方法,并声明它为before_filter。这样在所有的Controller 中,就可以利用它来进行权限的验证,如果验证不成功,就重定向到首页或报错,这很好的实现了程序的分层和隔离。但有些Controller中既包含一些让所有人访问的action,也包含一些需要验证的action。
拿我的BlogController 举例来说明:不需要验证的actions 有index, show 和rss;需要验证的有new, create, edit, update 和destroy。那么就有两种方式来区分这些actions。一种是:
skip_before_filter :authorize, :except => [:new, :create, :edit, :update, :destroy]
另一种是:
skip_before_filter :authorize, :only => [:index, :show, :rss]
两种的结果是一模一样的,但我偏向于后者。理由如下:
- 如果你增加一个新的不需要验证的action,譬如comment,对于第一种,你的确省了点事,skip_before_filter那一行不用修改任何代码,你新加的测试也都不会有一点问题;但要是你新加一个需要验证的action,譬如soft_delete,你的测试也没考虑到是否要验证,同时你也忘记了在Controller 中except 它,那么测试全过,但安全性却无法保障,知道这个接口的任何人都可以软删除你的任何博文。但是对于第二种,如果你忘记登入,那么测试会失败,因为会重定向到首页或报错,这就告诉你这个action 的正确行为。
- 这个理由可能有点牵强,我觉得第二种方式对于中国人的思考方式更好阅读,可能中国人对于unless和except 这种方式不太习惯吧,至少我是这样的。我们习惯于说话正着说,不喜欢把东西放在最后,还要转折那么一下。
好了,今天就是这么一点小小的思考。
If you want you product embedded Google search, you can try to use Google AJAX Search API to do it and customize the look and feel. However, you still need to do a lot work to make it prettier.
Let’s say you want to add “previous page” and “next page” link to the pagination. The weird thing is Google AJAX Search API doesn’t render all the page links as “link”, they just stylize those div and use Javascript to send request. I thought it is almost impossible until later I found the Searcher has method gotoPage(page). This make your life much easier. So the code is like this:
var previousLink = new Element('div', { 'id': 'prev-link', 'class': 'gsc-cursor-page' }).update('« Previous Page');
previousLink.observe('click', function(event) {
this.searcher.gotoPage(this.searcher.cursor.currentPageIndex - 1);
}.bind(this));
This piece of code creates a div using javascript (prototype style) as previous page link, and observe the click event. Call searcher’s gotoPage() method after click previous link and set page cursor minus one. After create this previous page link element, you just need to insert it in the correct position. Then that’s it, it works :D
Developers like to discuss the preference js library from jQuery to Prototype. I am not writing this post to say I would like to choose one of them. Actually I want to tell you some ways to combine them together.
jQuery is easy to use, faster and have many advanced plugins, but Prototype is more powerful and you can have a native helper methods embedded in Rails if you are using Rails to develop something. So I would like to show you 2 ways of combine them together in one application
1, jQuery official web site way : You can use jQuery.noConflict() method to announce you are using some other libraries with. Then from now on you can use jQuery as namespace instead of our favorite symbol $. Or you can provide an alias name for $ for example “var $j = jQuery.noConflict();”, then you can use $j instead of $. I don’t like this way to be honest. It will confuse people and it is inconvenient to me. Usually people who are using jQuery they don’t need to use prototype at the same time, vice versa. So here is my way
2, In this way I use some specific Rails features. I use asset packager to merge my javascripts and stylesheets. So my asset_packages.yml file may look like this:
--- javascripts: - prototype: - prototype - jquery: - jquery stylesheets: - base: - scaffold
Now you see I have two different sets of javascripts, one is prototype and the other is jquery. My layout file header in html may look like this:
<head> <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> <title><%= controller.action_name %></title> <%= yield :javascirpts %> <%= stylesheet_link_tag 'scaffold' %> </head>
“yield :javascripts” tells Rails I will declare javascripts into header later. Then the most important parts, suppose I have two files(listing projects and new project), for listing projects I want to use Prototype and the other I want to use jQuery.
<% content_for :javascirpts do %>
<%= javascript_include_merged :prototype %>
<% end %>
<h1>Listing projects</h1>
<table>
<tr>
</tr>
<% @projects.each do |project| %>
<tr>
<td><%= link_to 'Show', project %></td>
<td><%= link_to 'Edit', edit_project_path(project) %></td>
<td><%= link_to 'Destroy', project, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New project', new_project_path %>
The most important part is using “content_for :javascripts” block to use prototype. The other file is similar but use jquery library.
<% content_for :javascirpts do %>
<%= javascript_include_merged :jquery %>
<% end %>
<h1>New project</h1>
<% form_for(@project) do |f| %>
<%= f.error_messages %>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
<%= link_to 'Back', projects_path %>
But this probably means you need to maintain two sets of javascripts code. That may cost a little bit much than just using one library. You need to consider before you really want to do this.
才搬到三番三个礼拜,就遇见了许多有趣的人,也找到了称心如意的房子,以后可要好好的在这里生活一段时间了。
找房阶段遇到了许多有趣的人,首先是遇到了一位为自己理想拼搏的歌手,她原来是一位业务分析师,后来想学唱歌就辞职了,最近在一个乐团里作为主唱。今晚我就去看了她们乐队在一个酒吧的表演,她的演出绝对一流。实际上她也即将成为我在同一栋别墅里居住的室友。找房阶段还认识了一位Berkeley的女博士,主修东方文化,那次和她聊了很多关于佛教的东西,扯来扯去,竟然聊到了中国的GFW和韩寒。她说中国的GFW迟早会完蛋的,只是时间问题,言论自由就像煮沸开水里的气泡,最后锅盖再大也挡不住。真的希望像她说的这样。
今天晚上还通过Maria(上面提到的那位歌手),认识了一位在Pixar做开发的程序员,竟然邀请我以后去Pixar参观下,这实在是太令人激动了!还认识了一位Graphic Designer,他竟然设计过火影忍者的一些角色。希望以后还有见面的机会,三番真是个神奇而美丽的城市。不知道未来还会发生什么神奇的事情呢,真是让人期待啊!
The meaning of ‘hijack’ means switching some content with something else. So our team just found one big security issue with Apache and Jetty 6.1.5. This issue only happens when they combine together. The case is like this: user_one login, and user_two login with a blank cookie. Then the second user just get all the cookie from the first user.
This is interesting, isn’t it? It takes the whole dev team more than one week to discover it. I need to record it down, when my mind is so clear on this. The reason behind this is Apache and Jetty kind of keeping some state between each other. Yes, you are right, HTTP should not contain any state. But it is weird that Apache and Jetty, this combination does. BTW, We are using mod_proxy in Apache. So if the second user doesn’t have cookie, then the jetty will think the state is not correct, this is like a transaction, it automatically rollback the connection, give the cookie to second user, then the second user login as the first user.
Imaging if it is a bank system, that would be so interesting for you to login as Bill Gates.
The fix is simple, upgrade jetty to 6.1.19, this version has fixed this problem. Hoping this can help you if you are trying to figure out what is going on your Apache and Jetty
Yes, I am a software developer, not a hardware engineer. I am not going to talk anything about hardware memory, I am going to tell you something related to a true software story, :D.
Since I went to college to study computer science, I always heard people saying, the more memory the faster. So I always believe that if you machine have more memory your machine will become faster, until this morning, I learnt something from my tech lead Badri . He says no to me, and explained all the reason. He totally changed the concept I brought from school.
The answer is it depends. OK OK, I am not tricking you. I will tell you why. For example if your machine has 4GB memory, and there is one app running based on Java, and it use all the 4GB. And suddenly your app memory usage boomed to 4GB, then GC starts, and your machine will be dead.
What does this mean? You should know that Java does GC as soon as it reaches the memory limit. The more memory you have the longer it will take of GC. If we only have 2GB memory, then it will take less time but frequent GC, will will reduce a lot of pain. So we should memorize this: It depends.
Try the attached gem file first, if it doesn’t work then follow these steps
You can download the gem file from Here
First, try to use command ‘sudo gem install stemmer4r’, yeah, you get an error, that is right, don’t clean up your screen yet. It will give your the stemmer4r gem path you installed, mine is /Library/Ruby/Gems/1.8/gems/stemmer4r-0.6, maybe yours is different.
Go to that directory search the entire gems directory and replace ’/usr/local/ruby/lib/ruby/1.8/i686-linux’ to be something like ’/System/Library/Frameworks/Ruby.framework/Versions/1.8/Headers’, because your ruby headers are in this directory, you are not using Linux, right?
Go to /Library/Ruby/Gems/1.8/gems/stemmer4r-0.6/ext/stemmer4r folder, and modify the extconf.rb file ,replace the first line from ’#!/usr/bin/ruby -w’ to ’#ruby -w’
Stay in this directory and do command ‘sudo make’
Go to ’/Library/Ruby/Gems/1.8/gems/stemmer4r-0.6’ and type command ‘gem build stemmer4r.gemspec’
Then you got your own stemmer4r-0.6.gem file and you can do ‘sudo gem install stemmer4r-0.6.gem’, succeeded? Good job!
I have read a blog post about Ruby functional programming, in his example he uses Quick Sort algorithm , after read his post , I found myself really like his final solution, I think it is a good example of Ruby’s beauty, and I tried to refactor it a little bit like this:
def quicksort(items)
return [] if not items or items == []
x, *xs = items
quicksort(xs.select { |i| i < x }) + [x] + quicksort(xs.select { |i| i >= x })
end
It only contains 3 lines of code and it is even shorter than its pseudocode:
function quicksort(array)
var list less, greater
if length(array) ≤ 1
return array
select and remove a pivot value pivot from array
for each x in array
if x ≤ pivot then append x to less
else append x to greater
return concatenate(quicksort(less), pivot, quicksort(greater))
Isn’t it beautiful? Do you like this kind of beauty, then start to learn Ruby now!
