程序员…
4 May
带了一个moto 的 milestone回来,到家发现我的mac无法给他充电,查了好大一会,找到一个解决的办法,如下:
按照http://blog.gruby.com/2006/11/27/charging-a-motorola-razr-over-usb/ 这个文章说的,下载一个motocharger.app.zip ,然后解压放在applications目录下,运行就可以充电了。
原因不晓,感兴趣的自己链过去了解~
27 Apr
一个项目用到了图片上传,不想自己写处理过程了,于是就找找可以使用的插件,看到了Paperclip,大概了看了下代码和使用介绍,比较简洁。
装上测试了下,整个过程比较顺利,很快就集成了需要的功能,但是具体到我的需求 上,花了点时间,我的需求也比较常见,就是大量的图片不能就存在一个文件夹下(否则这么多的小文件会带来很多的隐患),于是看代码找找其是否支持分目录的方案,我直接基本上都是按时间来分成诸如”2010/0428/”这样的目录,但是找了一圈,发现其提供了timestamp的一个变量,但是其结果比较糟糕,文件夹中还会根据当代的locale出现一些等下,不太合适;
然后看到其提供了一个:id_partition的参数,其意思是:
# Returns the id of the instance in a split path form. e.g. returns
# 000/001/234 for an id of 1234.
[paperclip] Saving attachments.[paperclip] saving /svnroot/eoe/dev/rails/eoemarket/eoeMarket/upload/shops/logos/2010/0428//5/original/me.jpg[paperclip] saving /svnroot/eoe/dev/rails/eoemarket/eoeMarket/upload/shops/logos/2010/0428//5/thumb/me.jpg[paperclip] saving /svnroot/eoe/dev/rails/eoemarket/eoeMarket/upload/shops/logos/2010/0428//5/small/me.jpg
参考:
http://jimneath.org/2008/04/17/paperclip-attaching-files-in-rails/
http://cn.asciicasts.com/episodes/134-paperclip
http://github.com/thoughtbot/paperclip
http://gist.github.com/165072
18 Apr
以前一个项目中直接使用了restful_authentication,耶没怎么管生成的密码是啥样的,最近有几个系统要对接,需要统一用户,于是看了下restful_authentication的密码加密原则,发现其真是负责,一共分成下面几个部分:
1.定义了一个40位的REST_AUTH_SITE_KEY和一样我常量10的REST_AUTH_DIGEST_STRETCHES;
2.随机生成一个salt,其salt生成的规则是secure_digest(Time.now, (1..10).map{ rand.to_s }),而secure_digest是Digest::SHA1.hexdigest来生成的,也是40位。
3.将salt和原始密码,混合前面定义的REST_AUTH_SITE_KEY,反复加密REST_AUTH_DIGEST_STRETCHES次,得到最终的一个digest就是密码了。
够复杂~ 为啥搞这么负责呢,直接随机salt加双MD5不可逆加密也应该够用了吧。
18 Apr
前面2个文章说到了在Rails中使用send_file实现断点续传《在rails下实现多线程下载和断点续传》和利用Nginx的X-Accel-Redirect实现发送大文件《使用Nginx的X-Accel-Redirect在Rails中发送文件》,项目中需要两个功能,就把他整合起来,同时发布到github上了,Nginx-X-Accel-Redirect。
简介:
This Rails plugin allows users to take advantage of nginx’s X-Accel-Redirect header, similar to X-Send-File and Content-Range.
安装:
$ script/plugin install git://github.com/IceskYsl/Nginx-X-Accel-Redirect.git
使用:
x_accel_redirect “/path/to/file”, :filename => “filename”,:root=>”/path/to/root”
18 Apr
很多时候,我们会遇到需要一些业务逻辑(例如鉴权)后才将文件发送给客户端,那么如果将附件保存在public目录下将是非常不合适的,为了安全起见,你最好是将其保存在客户端无法直接访问的到的目录下,在处理完业务逻辑后,在将文件发送给客户端,Rails中提供了 send_XXXX来发送文件;
但是使用Rails的app server(thin,mongrel,passenger etc.)来发送文件(特别是大文件)一直都不是一个靠谱的方案,rails提供的send_file和send_data在理论上是可以工作的,但是其会阻塞进程,消耗内存,等等系列的弊端,而诸如apache,Lighttpd,Nginx等web server在处理静态文件上有着得天独厚的优势。
于是聪明的人们就想,可以使用app server处理业务逻辑,然后再让web server来接管处理剩下的文件发送,所以就有了mod_xsendfile for Apache2和Lighttp中提供的X-Sendfile功能,Nginx自然也有类似的功能,只是其名字不叫X-Sendfile,而是叫X-Accel-Redirect(这个名字好像更容易理解)。 这里主要说Nginx,Apache的自行查阅资料,先了解下原理:
定义一段配置:
location /protected/ { internal; root /some/path; }
然后在你的应用中:
add_header("X-Accel-Redirect: /protected/iso.img");然后Nginx就接管了你的请求,发送/some/path/protected/iso.img这个文件。原理了解了,看看如何使用更快捷,自然是用插件,有人写出了一个插件:X-Accel-Redirect= X-Accel-RedirectThis Rails plugin allows users to take advantage of nginx's X-Accel-Redirect header, similar to X-Send-File.== Install You should install it as a plugin, running this command on your projects root directory: $ script/plugin install git://github.com/goncalossilva/X-Accel-Redirect.git== Usage X-Accel-Redirect has an equivalent method to Rails <i>send_file</i>, called <b>x_accel_redirect</b>. Using is as easy as: x_accel_redirect "/path/to/file", :filename => "filename" All <i>send_file</i> options are available using this method. Now you can even let your old <b>:x_sendfile</b> option since the plugin will discard it.参考:
wiki.nginx.org/NginxXSendfileUSING NGINX TO SEND FILES WITH X-ACCEL-REDIRECT
The complete nginx solution to sending flowers and files with rails
[译]利用Nginx的X-Accel-Redirect头实现下载控制(附带php和rails实例)
17 Apr
最近一个项目用到了断点续传的需求,找了一些资料,
ror下文件下载是通过send_file完成的,但是如果使用多线程并支持断点续传的客户端(FlashGet等),send_file是不能正确工作的,原因在于,send_file函数没有对HTTP协议的Range头做相应的支持,并且也不支持HTTP/1.1 206 Partial Content相应
我修改了send_file函数,并做了一个plugin 将起解压到vendor/plugins/就可以了
(必要的地方我都写了注释,欢迎大家提出建议和意见)
记录一下相关的code:
module ActionController
module Streaming
protected
def send_file(path, options = {})
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
options[:length] ||= File.size(path) # 文件长度
options[:filename] ||= File.basename(path) # 文件名称
options[:from] ||= 0 # 首偏移量(从哪里开始下载)
options[:to] ||= options[:length] # 结束位置
m_send_file_headers! options # 设置必要的 http 头
@performed_render = false
if options[:stream]
render :status => options[:status], :text => Proc.new { |response, output|
logger.info "Streaming file #{path}" unless logger.nil?
len = options[:buffer_size] || 8192 # 原来的实现是4K, 不过APUE 上说,8K 要好一些,所有我调整了一下
File.open(path, 'rb') do |file|
file.seek(options[:from].to_i, IO::SEEK_SET) if options[:status] == 206 # 如果是多线程下载,则将流定位到首偏移量位置,从此处开始传输
while buf = file.read(len)
output.write(buf)
end
end
}
else
logger.info "Sending file #{path}" unless logger.nil?
File.open(path, 'rb') { |file| render :status => options[:status], :text => file.read }
end
end
private
def m_send_file_headers!(options)
options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options))
[:length, :type, :disposition].each do |arg|
raise ArgumentError, ":#{arg} option required" if options[arg].nil?
end
disposition = options[:disposition].dup || 'attachment'
disposition <<= %(; filename="#{options[:filename]}") if options[:filename]
# 先输出一些通用的HTTP头
headers.update(
'Content-Type' => options[:type].strip, # fixes a problem with extra '\r' with some browsers
'Content-Disposition' => disposition,
'Content-Transfer-Encoding' => 'binary'
)
# 判断是否存在Range头,并使用正则表达式匹配 from 和 to
# 如果匹配成功,则表示客户端使用多线程下载,同时一定要将http status 设置为 206
if request.env['HTTP_RANGE'] =~ /bytes=(\d+)-(\d*)/ then # 注意后一个\d*,有一些多线程客户端并不完全符合http协议的要求(例如FlashGet)
options[:from] = $1
options[:to] = $2 unless $2.nil? # 如果客户端不标准,就将 to 设置为文件末尾
# 匹配成功,设置status 为 206
options[:status] = 206
# 一下3个http 头仅在多线程下载是有用
headers['Accept-Ranges'] = 'bytes'
headers['content-Range'] = "bytes #{options[:from]}-#{options[:to]}/#{options[:length]}" # 格式为 bytes from-to/total
headers['Content-Length'] = options[:to].to_i - options[:from].to_i + 1 # 注意 在多线程下载下,Content-Length 为传输的实际字节数(从0开始算起,所有要+1)
else
# 非多现场下载
options[:status] = 200 # 请求正常标志
headers['Content-Length'] = options[:length] # 非多线程下载下,Content-Length为文件长度
end
headers['Cache-Control'] = 'private' if headers['Cache-Control'] == 'no-cache'
end
end
end
用法:
class FileController 〈 ApplicationController def download #logger.debug request.env['Range']; # request.env.each do |key, value| # logger.debug key + '--------' + value # end send_file 'public/jdk.tgz' end end
1 Apr
昨晚看hero的时候顺带update到mac OS 10.6.3,早上重启机器安装成功,发现rails3无法启动,报:
/Library/Ruby/Site/1.8/rubygems.rb:334:in `bin_path’: can’t find executable rails for rails-3.0.0.beta (Gem::Exception)
from /usr/bin/rails:19
这个错误我之前安装rails3的时候遇到过,解决如下:
1.先尝试下重新安装rails
IceskYsl@eoe /svnroot/eoe/dev/rails/eoelogs $ sudo gem install rails –pre
Password:
Successfully installed treetop-1.4.5
1 gem installed
Installing ri documentation for treetop-1.4.5…
Installing RDoc documentation for treetop-1.4.5..
发现多了个treetop的gem,查查是啥:
Treetop is a language for describing languages. Combining the elegance of Ruby with cutting-edge parsing expression grammars, it helps you analyze syntax with revolutionarily ease.
再次执行rails,发现
/Library/Ruby/Site/1.8/rubygems.rb:334:in `bin_path’: can’t find executable rails for rails-3.0.0.beta (Gem::Exception)
from /usr/bin/rails:19
还是不行,那就是railties的问题了,重新装下
IceskYsl@eoe /svnroot/eoe/dev/rails/eoelogs $ sudo gem install railties –pre
Successfully installed railties-3.0.0.beta
1 gem installed
Installing ri documentation for railties-3.0.0.beta…
Installing RDoc documentation for railties-3.0.0.beta…
IceskYsl@eoe /svnroot/eoe/dev/rails/eoelogs $ rails -v
Rails 3.0.0.beta
OK,可以了~
31 Mar
很简单,就是在.bash_profile下加了三行.
export CLICOLOR=1
export LSCOLORS=exfxcxdxbxegedabagacad
另外加了一行个性化提示符.
export PS1=”\[\e[32;1;40m\]\u@\H \w \$ \[\e[0m\]”
相关的文章参见:
http://mac.linsheng.me/archives/530.html
http://www.ibm.com/developerworks/cn/linux/l-tip-prompt/tip01/
http://hi.baidu.com/rainfish_tju/blog/item/0f54458f849141f0513d9284.html
配置
那么应该怎样来配置成我喜欢的颜色呢?下面我们就来详细说一些这些配置。
~/.bash_profile是bash shell中当前登录用户的配置文件。bash是“终端”中默认的shell。
alias ls=”ls -G”是给”ls -G”起了一个别名,当执行ls时,就相当于执行了ls -G。
CLICOLOR是用来设置是否进行颜色的显示。CLI是Command Line Interface的缩写。
LSCOLORS是用来设置当CLICOLOR被启用后,各种文件类型的颜色。LSCOLORS的值中每两个字母为一组,分别设置某个文件类型的文字颜色和背景颜色。LSCOLORS中一共11组颜色设置,按照先后顺序,分别对以下的文件类型进行设置:
directory
symbolic link
socket
pipe
executable
block special
character special
executable with setuid bit set
executable with setgid bit set
directory writable to others, with sticky bit
directory writable to others, without sticky bit
LSCOLORS中,字母代表的颜色如下:
a 黑色
b 红色
c 绿色
d 棕色
e 蓝色
f 洋红色
g 青色
h 浅灰色
A 黑色粗体
B 红色粗体
C 绿色粗体
D 棕色粗体
E 蓝色粗体
F 洋红色粗体
G 青色粗体
H 浅灰色粗体
x 系统默认颜色
所以,如果我们想把目录显示成红色,就可以把LSCOLORS设置为bxfxaxdxcxegedabagacad就可以了
25 Mar
cache_fu在过期单个记录的时候很方便,但是对以那些列表分页的就有点弱了,没法过滤以制定前缀的key来过滤,所以变通下,需要用过loop来过滤,如下是个例子:
#expire_list_cache
def expire_caches
Song.expire_cache(self.id)
ApkFile.expire_cache(self.main_apk_file_id) if self.main_apk_file_id
AppStat.expire_cache("app_stat#{self.id}")
0.upto(PAGES) do |page|
SongScreenshot.expire_cache("song_screenshots#{self.id}#{page}#{PER_PAGE}")
Song.expire_cache("list_items_status_state:11#{"updated_at desc"}#{page}#{PER_PAGE}")
Song.expire_cache("list_items_in_category_status_state:#{self.category_id}11#{"updated_at desc"}#{page}#{PER_PAGE}")
Song.expire_cache("items_in_autthor:#{self.author_id}11#{"updated_at desc"}#{page}#{PER_PAGE}")
end
end
24 Mar
用了acts_as_taggable_on_steroid和will_paginate插件,发现不能分页,查找解决办法,如下得最方便:
options = Product.find_options_for_find_tagged_with(params[:tag_name],:order => “updated_at DESC”).merge(:page => params[:page] ||1,:per_page =>20 )
@products = Product.paginate(options)
Comments::最新评论