为什么我会建立rails-bestpractices.com网站呢?

首先, rails-bestpractices.com是一个提供rails最佳实践分享的网站,任何人都可以分享自己开发中的最佳实践,你也可以在这里同别人一起讨论,并选择自己喜欢的最佳时间。

其次,rails-bestpractices.com提供了问答的版块,当你在开发中遇到疑惑,不知道该用什么解决方案的时候,这里是你提问和解惑的好地方。

另外,这里也是rails_best_practices gem的官方地址,在这里会介绍rails_best_practices的实现,同时通过吸收大家的最佳实践,我会不断扩充rails_best_practices的功能。

以后我会介绍一些我开发rails-bestpractices.com网站的经验,希望对大家有帮助。

将table的数据导出为csv

2010-07-20 16:53:53 +0800

项目中经常会有这样的usecase,把一个table中的数据导出为csv,用fastercsv这个gem可以快速完成这个功能。

首先放一个导出csv的链接

= link_to 'Export to CSV', participants_path(:format => :csv)

然后在controller中生成相应的csv,并发送给用户

def index
  @participants = Participant.all
  
  respond_to do |format|
    format.csv {
      participants_csv = FasterCSV.generate do |csv|
        csv << ["First Name", "Last Name", "Age", "Gender", "Address", "Phone", "Email"]
        @participants.each do |p|
          csv << [p.first_name, p.last_name, p.age, p.gender, p.address, p.phone, p.email]
        end
      end
      send_data participants_csv, :type => 'text/csv', :filename => 'participants.csv'
    }
  end
end

其中用FasterCSV快速创建好csv数据,再通过send_data发送给客户端就可以了

今天参加rubyconfchina,再次聆听ihower的演讲,再次收益匪浅。

中间在听到Variable Scope突然想到可以使用RubyParser来检查,于是写了几行代码测试,果然是可行的。

ihower提到在ruby代码中只有在module,class和def才会创建Varible Scope,比如:

module MyDemo
  var = 1
  class Demo
    var = 2
    def foo
      var = 3
    end
  end
end

其中三个var都在不同的scope。这个在RubyParser的解析结果里面有体现出来。比如,ihower提到def会创建一个scope而define_method不会。我们可以用下面的代码来做个实验

text=<<-EOF
class Class
  def define_more_methods
    ["aaa", "bbb", "ccc"].each do |name|
      define_method(name) do
        puts name.upcase
      end
    end
  end
end
EOF
RubyParser.new.parse(text)

它的解析结果为

s(:class, :Class, nil, 
  s(:scope, 
    s(:defn, :define_more_methods, s(:args), 
      s(:scope, 
        s(:block, 
          s(:iter, 
            s(:call, 
              s(:array, s(:str, "aaa"), s(:str, "bbb"), s(:str, "ccc")), 
              :each, 
              s(:arglist)
            ), 
            s(:lasgn, :name), 
            s(:iter, 
              s(:call, nil, :define_method, s(:arglist, s(:lvar, :name))), 
              nil, 
              s(:call, nil, :puts, s(:arglist, s(:lvar, :name)))
            )
          )
        )
      )
    )
  )
)

可以看到class有创建一个scope,defn也有创建一个scope,而define_method却没有。同样地,你也可以通过实验看到class_eval和instance_eval都没有创建scope。完全和ihower讲的一样。

以后要是什么时候碰到Variable Scope的问题,就可以使用RubyParser来检查啦,实践见真知。

nginx上传进度条

2010-06-05 21:36:08 +0800

项目中经常需要应用的功能之一就是文件上传,一般对于小文件来说不需要特别的处理,但是一旦碰到允许大尺寸文件上传的时候,用户常常会被长时间的没有变化的上传过程而迷惑,这种时候就需要一个上传进度条来提醒用户。比如我最近一个项目允许用户上传100M的视频文件,上传的过程往往需要持续10多分钟,这种情况如果没有进度条的话,用户可能会以为系统出问题了。项目部署的环境为nginx+lighttpd,上传的过程是这样的:

1. 用户选择上传的视频,点击提交按钮

2. nginx将视频文件的二进制数据保存为/tmp目录下面的某个文件

3. lighttpd执行rails的代码对/tmp目录下面的上传文件进行处理

 由此可见,上传视频的过程都是由nginx进行处理的,lighttpd并不知情,它只能通过上传表单了解到上传到/tmp目录下的文件名,这样的好处是,费时的上传过程并不会消耗rails进程。所以我们在做上传进度条的时候就要在nginx身上下功夫了。

google了一下,发现网上已经有了解决方案,http://github.com/drogus/jquery-upload-progress

 

同时修改nginx配置文件 ,增加以下这段:

location ^~ /_upload_progress {
  upload_progress_json_output;
  report_uploads proxied;
}

应用jquery-upload-progress就是采用ajax轮询,请求/_upload_progress,返回一个json,告诉你上传是否开始,上传了多少字节,总共有多少字节,你只需要比较上传多少字节和总共多少字节就可以得到上传数据的进度,至于进度条的显示只需要些点css就可以搞定了。

方便地浏览github上所有的issues

2010-06-02 22:21:03 +0800

我在github上面有好几个repositories,经常会有人来报告报告issue,但问题是有时候手头正好有其它的事情需要处理,就没有办法马上修复issue,随着时间的推移,越来越多的issues被积压下来,而且是分散在各个repositories,这让我找起来很费力,必须首先进入repository页面,再点击issues,才能看到相应的issues。我想要是有个页面能够列出所有repositories的issues该多好啊,不过github上面好像没有找到这样的页面。没办法,只好自己动手丰衣足食。

github提供了api,这大大方便了开发,同时有相应的ruby实现octopi。剩下的工作就很简单了,创建一个sinatra项目,接受用户输入的github用户名,通过用户名获取到该github user,再通过user拿到repositories,通过repository拿到issues,最后通过issue拿到comments,所有的数据都轻而易举地获得了,接下来就是稍微美工一下,然后就发布到heroku上面。半天时间搞定,ruby开发就是个快啊。

heroku上面的地址是:http://github-issues.heroku.com/