fsword's blog

A blogging framework for hackers.

Sinatra-contrib没有自动装载

| Comments

最近写代码是基于sinatra的,遇到了一点小问题
在Gemfile中添加了sinatra和sinatra-contrib,但是实际使用中,sinatra-contrib没有被装入

1
2
3
# Gemfile
gem 'sinatra'
gem 'sinatra-contrib'

解决的办法是在启动脚本里面手工加上一行require

1
2
3
require "bundler"
Bundler.require(:default)
require 'sinatra/contrib'

但是这个方式有点土,其实如果换用新版的bundle就可以自动处理了

1
2
3
4
5
6
7
8
9
10
$ gem update bundle
Updating installed gems
Updating bundler
Fetching: bundler-1.1.3.gem (100%)
    Successfully installed bundler-1.1.3
    Updating rubygems-bundler
    Fetching: rubygems-bundler-0.9.2.gem (100%)
    Building native extensions.  This could take a while...
    Successfully installed rubygems-bundler-0.9.2
    Gems updated: bundler, rubygems-bundler

需要说明的是,bundler1.1目前在网站上写的还是 coming soon,不过新功能还是值得尝试的
顺便附上 bundler 的 changlog

Active Record错误汇总

| Comments

这个帖子专门记录一些使用active record时遇到的错误
1. 错误描述:directive找不到自己的template
错误代码

1
2
3
4
5
6
7
8
9
10
class Directive
  belongs_to :template, :class_name => 'DirectiveTemplate'
  ...
end

create_table "directives", :force => true do |t|
  ...
  t.integer  "directive_template_id"
  ...
end

解释:这段代码本身并没有错误,问题是建立directives表的时候给字段命名为 directive_template_id。事实上,active record使用关联对象的外键,是根据field名称来进行的,它和设置的class_name,所以ar会根据directive对象的template_id字段查找关联的template
解决方法:更改数据库字段名,或者在模型代码中指定foreign_key

  1. 错误描述:db:seed_fu 创建模型遇到表结构错误
    解释:初步试验发现,如果执行 rake db:create db:migrate db:seed_fu 会遇到这个问题,而将seed_fu单独执行则是正常的,考虑到发生错误的表在migrate阶段有过结构变更,估计是数据库事务导致alter语句没有提交,从而使得seed_fu失败

Vagrant使用步骤总结

| Comments

使用vagrant把AppOSS的项目环境打了一个包,这个东西确实很适合统一开发环境,总结一下过程吧。

基于base.box或者某个os的iso文件建立基础系统环境,相关命令为

1
2
3
4
vagrant add base <base box url>
cd <your rails project>
vagrnat init base
vagrant up

调整系统环境,相关命令为

1
2
vagrant ssh
curl -L get.rvm.io | bash -s stable

将调整过的环境打包为新的base文件,以备将来使用,相关命令为

1
vagrant package --output base-ubuntu-rvm.box

修改Vagrantfile,添加puppet支持,相关内容为

1
2
3
4
5
# Vagrantfile
config.vm.provision :puppet do |puppet|
  puppet.manifests_path = "manifests"
  puppet.manifest_file  = "ubuntu.pp"
end

将项目依赖的软件包(例如:libxml2-dev,libmysqlclient-dev之类),通过puppet安装好,相关命令为

1
vagrant reload

重新打包为box文件,这就是可以重复使用的项目环境了

1
vagrant package --output apposs-center.box

说明:
1. 对于团队协作而言,如果环境有了变化,重复5、6两步即可
2. 将rvm放在自己定制的base中是考虑到其它项目也会用到rvm,原则上,项目专用的环境通过puppet进行统一,各项目都有的环境使用同一个base box来解决
3. ruby项目通过bundle管理的gem包,可以采用下面的命令进行安装,这样可以减少内外系统的重复文件

1
bundle install --path ./vendor/bundle

这个做法是来自saberma同学,原文在此: http://saberma.me/linux/2011/03/03/vagrant-virtual-develop-enviroment.html

Vagrant环境

| Comments

vagrant是一个基于Virtual Box的ruby工具库,它可以很简单的管理你的开发和运行环境 官方网站:http://vagrantup.com/

今天准备了一个干净的运行环境,步骤如下:

修改locale

1
2
vi /etc/default/locale #将 LANG 改为 zh_CN.utf8
sudo locale-gen zh_CN.utf8

安装必要的本地库

1
2
sudo apt-get install mysql-server libmysqlclient-dev git
sudo apt-get install libxslt-dev libxml2-dev

用rvm安装ruby

1
2
3
4
5
6
curl -L get.rvm.io | bash -s stable
source .bashrc
rvm pkg install zlib
rvm pkg install readline
rvm pkg install openssl
rvm install ruby-1.9.3

进入 /vagrant 目录,准备rails环境

1
2
rake db:create db:migrate
rails s

后续结合puppet来进行环境管理

让bash提示符显示彩色的git_branch

| Comments

之前一直很羡慕zsh用户,今天终于让bash也能显示彩色branch了 具体做法:修改你的 .bashrc,添加下面几句就可以了

1
2
3
4
5
parse_git_branch() {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/[\1]/'
}                    
_PS1=$PS1                                                 
PS1="\[\e[36m\]\u:\[\e[32m\]\w\[\e[33m\]\$(parse_git_branch)\[\e[0m\]\$ "


很简单,不过之前遇到了点麻烦:添加了彩色支持以后发现对较长的命令行会显示错误,后来发现是把\[\e[36m\]写成了 \[\e[36m(丢了后面的部分),汗

通过drb集成java和ruby环境

| Comments

ruby在很多方面都很不错,但是java也有它的优势,至少我们有很多基于java的遗留系统。
结合这两者主要有几种思路:
* 使用消息系统链接java应用和ruby应用,这是我们通常整合异构系统的思路
* 基于java的分布式设施进行系统整合,这要将ruby放在jvm上工作,我们可以用jruby on rails
* 基于ruby的 drb 技术进行系统整合,我们同样需要借助 jruby 让java系统看起来象 ruby
前两个不用举例,最后一个给一个简单的示例

1
2
3
4
# server.rb
require 'drb'

DRb.start_service('druby://localhost:9000', self)

以上的代码如果在 rails console 上执行,就可以使用如下代码进行远程调用了:

1
2
3
4
5
6
7
# client
require 'drb'

DRb.start_service
this = DRbObject.new(nil, 'druby://localhost:9000')

this.class_eval 'Rails.application.config.root'

Have fun!

Cucumber使用备忘

| Comments

cucumber 使用的时候默认的环境是 test ,此时配置信息为 config/environments/test.rb
当然我们也可以使用独立的 cucumber ,修改 config/database.yml 如下:

1
2
3
4
5
6
7
8
production:
  <<: *defaults
  database: app_development


cucumber:
  <<: *defaults
  database: app_cucumber

此时需要复制 test.rb 为 cucumber.rb
$ cp config/environments/test.rb config/environments/cucumber.rb
这时需要注意,如果你使用transaction进行数据清理,那么要设置 config.cache_classes = true,否则会收到错误信息

1
WARNING: You have set Rails' config.cache_classes to false (most likely in config/environments/cucumber.rb).  This setting is known to cause problems with database transactions. Set config.cache_classes to true if you want to use transactions.  For more information see https://rspec.lighthouseapp.com/projects/16211/tickets/165.

不过,如果这样,rails s启动的服务器将不会热更新代码,这点需要注意
我自己的做法是,支持热更新,但是不使用 transaction 方式支持数据清理

不常用的git命令

| Comments

git remote prune

说明:remote上的一个分支被其他人删除后,需要更新本地的分支列表
使用举例:

1
2
3
4
5
6
7
8
9
10
11
$ git branch -a
* master
  remotes/origin/master
  remotes/origin/other
$ git remote prune origin
Pruning origin
URL: git@github.com:fsword/my_project.git
 * [pruned] origin/other
$ git branch -a
* master
  remotes/origin/master

git push -f origin master

说明:强制push本地代码,例如在本地进行 amend 模式的commit的时候,实际上是重写了原来的commit,如果直接push会出错,此时需要强制push,让remote端与本地一致
使用举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git commit --amend -m 'this is a new comment'
To /home/john/proj_repo
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to '/home/john/proj_repo'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.
~/personal/temp2(master) $ git push -f origin master 
$ git push -f origin master 
Counting objects: 3, done.
Writing objects: 100% (3/3), 260 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /home/john/proj_repo
 + a11c377...93ef44d master -> master (forced update)

要说明的是,如果要做这个试验,需要确保remote允许push,如果你像我一样remote和work都是本地目录,那么remote那里要设置一下 .git/config 这个文件,增加这么一段

1
2
[receive]
    denyCurrentBranch = ignore

另外,对于pull的一方,操作也要稍微调整一下:

1
2
git fetch origin
git reset --hard origin/master

git checkout [COMMIT_ID] [FILE_PATH]

说明:部分恢复。当我们修改很多次之后,可能想恢复之前某个commit时的某个或者某些文件,本命令就提供了这个支持。 使用举例:

1
git checkout acfc7ea462fa6f4425be251c2076d10a5fbde0ba images/old_way_new_way.*

have fun!

Fixture使用时需要注意的问题

| Comments

单测时不太顺利,主要是fixture使用不熟悉,记录两个问题

bug 1:经过定位发现是fixture数据始终不能灌入导致的

1
2
3
4
5
6
machine1:
  id: 1
  app_id: 1
machine1:
  id: 2
  app_id: 1

期望有两条数据,实际只有一条,原因是在rspec灌数据时装载yml,而这里的数据是个hash,结果key相同(都是“machine1”)的entry被覆盖了,后一条被装入。
解决办法是:检查并修改重名的fixture条目,确保不冲突

bug 2:经过定位发现是fixture数据导入时,某个条目出错

1
2
3
4
5
something:
  id: 2
  app_id: 1
  name: package
  expression: 1,2

这里的 expression 值期望为字符串 1,2 ,然而最后总是变成 12,后来才发现是格式问题,对于,这种特殊字符,不能省略字符串的双引号,改为 “1,2”
解决办法是:检查并修改fixture条目中的格式特别的字符串,确保使用双引号包含