核心使用 task 指令 实现多机部署
# encoding:utf-8 # >cap local deploy # >cap remote deploy set :application, "entos" set :deploy_to, "/data/projects/entos" set :scm, "git" set :repository, "git@114.255.155.167:entos.git" set :branch, "master" set :use_sudo, false set :rails_env,"production" task :remote do set :user, "entsea" set :deploy_via, :remote_cache set :copy_exclude, %w(external) server "114.255.155.166", :web, :app, :db, :primary => true end task :local do set :user, 'zzq' set :deploy_via, :remote_cache set :copy_exclude, %w(external) server '192.168.10.105', :web, :app, :db, :primary => true end namespace :deploy do task :start do; end task :stop do; end desc "Creating ln -s , example: database.yml" task :create_sync do run "ln -s #{shared_path}/config/database.yml #{current_path}/config/database.yml" end desc "Restarting unicorn" task :restart, :roles => :app, :except => { :no_release => true } do # run "/bin/sh restart_server.sh" end end after "deploy:symlink", "deploy:create_sync"
今天一个同事 问我 正则 里 ?: 什么意思,记得 以前知道的 , 愣是 忘记了 ,查了下 是非捕获组的意思!
捕获组
()内的是分组,可以用 $1,$2…取值
demo:
ruby-1.9.2-p290 :022 > "abcabc".match(/(abc)/) => #<MatchData "abc" 1:"abc"> ruby-1.9.2-p290 :023 > $1 => "abc"
非捕获组
(?:) 内的不当作分组
demo:
ruby-1.9.2-p290 :024 > "abcabc".match(/(?:abc)/) => #<MatchData "abc"> ruby-1.9.2-p290 :025 > $1 => nil
时间: 2011-07-24
收获:
发现北京ROR的公司不是一般的多,签到单上看到N多公司,技术上没有太大收获,都是介绍性的,没有实战性的,内容主要涉及: mirah , Mongodb,Erlang,Grape
进程:http://www.surveymonkey.com/s/MSY2L7T
PS : 798 很好玩,很有艺术特色
现场:
798 入口
Ruby活动地方
Rails rumble 创始人
现场job board
现场
清一色老外,清一色Mac
介绍Mirah
798
798
798
一个rails2.x 的项目,需要迁移到rails3.x , ruby 1.9.2的编码问题,需要在rb文件头添加指定编码, 常见指定方式如下:
#coding:utf-8 #encoding:utf-8 # -*- coding: utf-8 -*- # -*- encoding: utf-8 -*-
那么多rb文件总不能一个一个加吧,写个shell解决之!!!
yaml 的语法真是变态 , 表示个数组这么麻烦, 更复杂的数据结构 那不是更麻烦 !!!
yaml 文件:
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html one: name: MyString orgunit_id: 1 inheritable: false # codes 是yaml数组表示方法 # 缩进只能是两个空格为一级,不能是其他字符 codes: - 1 - a - 2 - b - 3 - c
ruby 解析yaml:
ruby-1.9.2-p0 > file = "#{Rails.root}/test/fixtures/enumerations.yml" => "/usr/local/system/projects/entos/ent_os/test/fixtures/enumerations.yml" ruby-1.9.2-p0 > YAML.load File.read(file) => {"one"=>{"name"=>"MyString", "orgunit_id"=>1, "inheritable"=>false, "codes"=>[1, "a", 2, "b", 3, "c"]}}
不知道怎么写的可以 使用 to_yaml 方法 看一下:
irb(main):001:0> => {"one"=>{"name"=>"MyString", "inheritable"=>false, "orgunit_id"=>1, "codes"=>[1, "a", 2, "b", 3, "c"]}} irb(main):002:0> require "yaml" => true irb(main):003:0> hsh.to_yaml => "--- \none: \n name: MyString\n inheritable: false\n orgunit_id: 1\n codes: \n - 1\n - a\n - 2\n - b\n - 3\n - c\n"
可读性 更好的 使用 y 方法
ruby-1.9.2-p0 > y hsh --- one: name: MyString orgunit_id: 1 inheritable: false codes: - 1 - a - 2 - b - 3 - c => nil
环境:ruby 1.9.2 + rake 0.8.7 + rails 3.0.3
今天在写 rake 文件 , 提示我没找到 model Class,问题在于我没加 => :environment , 那为什么加上 => :environment 就可以了 , 研究了下rake:
task :test => :environment do end
其中后面的 :environment 也是 一个 task , 也就是说在执行 test 这个 task 之前 会执行 :environment 这个 task,有点像rails controller 中的 before_filter ,那么 :environment 这个task 定义在什么地方,rails project中也没有啊 。。。,定义在 rails 源码中了 ,你在 你的project下执行 rake environment 不会报错的
wxianfeng@ubuntu:/usr/local/system/projects/entos/ent_os$ rake environment --trace (in /usr/local/system/projects/entos/ent_os) ** Invoke environment (first_time) ** Execute environment
不过 也看不到 输出什么信息,因为只是加载了 运行环境而已 ,那么从哪里执行的,定义在 project 下 Rakefile 中了
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
EntOs::Application.load_tasks继续跟踪 load_tasks:
最后 找到了 task environment
def initialize_tasks
require "rails/tasks"
task :environment do
$rails_rake_task = true
require_environment!
end
end
全部文件 here
所以加载了 environment 也就可以 找到 model Class 了
总结:
1,rake 命名格式
rakefile, Rakefile, rakefile.rb, Rakefile.rb 都可以 ,常用 Rakefile
另外 rails 中使用的话,还可以 使用 .rake 后缀的文件
2,设置命名空间
namespace :test do end
3,设置默认task
task :default => ["test"]
可以指定多个 task,执行 rake 后 ,默认调用的是 default task
4,指定task执行顺序
task :test => [:hello,:world]
5,查看rake 任务
rake -T rake --tasks rake -T db: # 查看db打头的task
6,跟踪task
rake test --trace
更多 options
wxianfeng@ubuntu:/usr/local/system/projects/entos/ent_os$ rake -h rake [-f rakefile] {options} targets... Options are ... -C, --classic-namespace Put Task and FileTask in the top level namespace -D, --describe [PATTERN] Describe the tasks (matching optional PATTERN), then exit. -n, --dry-run Do a dry run without executing actions. -e, --execute CODE Execute some Ruby code and exit. -p, --execute-print CODE Execute some Ruby code, print the result, then exit. -E, --execute-continue CODE Execute some Ruby code, then continue with normal task processing. -I, --libdir LIBDIR Include LIBDIR in the search path for required modules. -P, --prereqs Display the tasks and dependencies, then exit. -q, --quiet Do not log messages to standard output. -f, --rakefile [FILE] Use FILE as the rakefile. -R, --rakelibdir RAKELIBDIR, Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib') --rakelib -r, --require MODULE Require MODULE before executing rakefile. --rules Trace the rules resolution. -N, --no-search, --nosearch Do not search parent directories for the Rakefile. -s, --silent Like --quiet, but also suppresses the 'in directory' announcement. -g, --system Using system wide (global) rakefiles (usually '~/.rake/*.rake'). -G, --no-system, --nosystem Use standard project Rakefile search paths, ignore system wide rakefiles. -T, --tasks [PATTERN] Display the tasks (matching optional PATTERN) with descriptions, then exit. -t, --trace Turn on invoke/execute tracing, enable full backtrace. -v, --verbose Log message to standard output. -V, --version Display the program version. -h, -H, --help Display this help message.
DEMO:
wxianfeng@ubuntu:~/test/rake$ cat Rakefile desc "Default: test" task :default => ["r:test"] namespace :r do desc "test" task :test do puts "test" end desc "test1" task :test1 => :test do puts "test1" end desc "test3" task :test3 => :test4 do puts "test3" end end
SEE:
http://hi.baidu.com/%D0%C7203/blog/item/ebda2dd09f1d698ea1ec9c7a.html
http://guides.rubyonrails.org/command_line.html
http://ericzouthoughts.wordpress.com/2009/06/20/execute-shell-command-in-ruby-rake-task/
环境:ruby 1.9.2
有这样一个需求, 给你 任意一个字符串,把它转化为类,网上大多数的 解决办法是 下面三种:
Kernel.const_get(:User) # Object.const_get(:User) eval(’User’) ‘User’.constantize
但是上面三种方法, 这个 User 事先必须是初始化的,不然会报错,如下:
Object.const_get(:User) # uninitialized constant User (NameError)
所以需要加个判断 这个 Class 有没有初始化,没有的话 再set 一个Class
require "rails/all" def Kernel.const_missing(name) Object.const_set(name,Class.new) end #p Kernel.const_get("baoxiaos".to_sym) # wrong constant name baoxiaos (NameError) p Kernel.const_get("baoxiaos".classify.to_sym) # Baoxiao , const的首字母必须大写 p Kernel.constants # [] p Object.constants.include?(:UBaoxiao) # true
刚开始把这个 const 定义在 Object 里:
require "rails/all" def Object.const_missing(name) Object.const_set(name,Class.new) end #p Object.const_get("baoxiaos".to_sym) # wrong constant name baoxiaos (NameError) p Object.const_get("baoxiaos".classify.to_sym)
发现 用在 rails 中后 , rails 处处报错,可能 怪我重写了 Object.const_missing 导致的 ……..
上面方法的原理是 当找不到 const的时候 执行了
Object.const_set(name,Class.new)
那么 name 就变成是 Class 的实例了 , 为什么定义在 Kernel 中的 const_missing ,Object 也可以访问到,需要注意 Object,Kernel 之间的关系,Object 是 inluce Kernel 的,如下:
class Object include Kernel end
SEE:
http://niczsoft.com/2010/01/string-to-class-in-ruby-on-rails/
http://www.ruby-forum.com/topic/96222
环境:ruby 1.9.2 + rails 3.0.3
我们经常会有这样的操作:
user = User.find_by_login("wxianfeng") # => nil user.name # => NoMethodError: undefined method `name' for nil:NilClass
假如 login 为 wxianfeng 不存在 ,会报错:
NoMethodError: undefined method `name' for nil:NilClass
那么建议使用 try 方法避免报错,try 返回的是 nil
user.try(:name) # =>nil
也就相当于
nil.try(:name) # => nil
看下源码: here
其实就是调用了 __send__ 方法 , __send__ 方法 和 send 方法等价 , 只不过 __send__ 方法 为了防止 有已经存在的 send 方法 , nil 的话 调用 NilClass 的 try 方法
另外 发现 github上 try方法已经重新写了 ,如下: here
class Object
# Invokes the method identified by the symbol +method+, passing it any arguments
# and/or the block specified, just like the regular Ruby <tt>Object#send</tt> does.
#
# *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
# and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
#
# If try is called without a method to call, it will yield any given block with the object.
#
# ==== Examples
#
# Without try
# @person && @person.name
# or
# @person ? @person.name : nil
#
# With try
# @person.try(:name)
#
# +try+ also accepts arguments and/or a block, for the method it is trying
# Person.try(:find, 1)
# @people.try(:collect) {|p| p.name}
#
# Without a method argument try will yield to the block unless the reciever is nil.
# @person.try { |p| "#{p.first_name} #{p.last_name}" }
#--
# +try+ behaves like +Object#send+, unless called on +NilClass+.
def try(*a, &b)
if a.empty? && block_given?
yield self
else
__send__(*a, &b)
end
end
end
class NilClass #:nodoc:
def try(*args)
nil
end
end
其实只是判断了 if a.empty? && block_given? 这种情况 则直接执行block 内容然后返回,效果一样…..
DEMO:
require "active_support/core_ext/object/try" class Klass def send(*args) "helo " + args.join(' ') end def hello(*args) "Hello " + args.join(' ') end def self.foobar(s) "#{s} foobar" end end k = Klass.new # __send__ 为了防止有方法名叫send , 建议用 __send__ p k.__send__ :hello, "gentle", "readers" #=> "Hello gentle readers" p k.send "gentle", "readers" #=> "Helo gentle readers" # Ruby 里一切皆是对象,类也是对象 # Klass(类) 是 Class 的实例 , Class 是 Object 的实例 , 那么 Klass 也就是 Object 的实例 所以 Klass 可以调用try 方法 p Klass.try(:foobar,"hey") # => "hey foobar" # k 是Klass 的实例,Klass 的父类是 Object , 所以 k 可以调用 try 方法 p k.try(:send,"bla","bla") # => "helo bla bla" # class 得到的是 实例关系 # superclass 得到的是 继承关系 p Klass.superclass # Object p Klass.class # Class p k.class # Klass
另外 这是 对象nil 那如果 没有那个字段了 , 就会 报 找不到方法的错误
例如:
ruby-1.9.2-p0 > u=User.first User Load (175.8ms) SELECT `users`.* FROM `users` LIMIT 1 => #<User id: 1, login: "entos", name: "", email: "entos@entos.com", crypted_password: "557c88b0713f63397249f4198368e4a57d6d400f", salt: "4e04ef1cf506595ac3edf6a249791c55995b0f8f", remember_token: nil, remember_token_expires_at: nil, activation_code: nil, activated_at: nil, status: 2, suspend_at: nil, avatar_id: nil, orgunit_id: nil, mobile_phone: nil, last_login_at: nil, language: nil, options: nil, created_at: "2011-02-24 02:55:42", updated_at: "2011-02-24 02:55:42"> ruby-1.9.2-p0 > u.hi NoMethodError: undefined method `hi' for #<User:0x9fcfe00>
建议加上 respond_to? 判断
ruby-1.9.2-p0 > u.respond_to? "hi" => false
环境:ruby 1.9.2 + rails 3.0.3
我们经常需要在 rails console 中进行Model的操作,想看执行的sql ,必须到 rails log 中去查看 , 现在 有一个更好的办法,直接输出到 console 中…
在console 运行下面这句话即可:
ActiveRecord::Base.logger = Logger.new(STDOUT)
或者 直接写到 config/appliction.rb 中 ,下次启动console的时候 不需要在写上面语句:
if Rails.env == 'development' ActiveRecord::Base.logger = Logger.new(STDOUT) end
DEMO:
wxianfeng@ubuntu:/usr/local/system/projects/entos/ent_os$ rails c Loading development environment (Rails 3.0.3) ruby-1.9.2-p0 > ActiveRecord::Base.logger = Logger.new(STDOUT) => #<Logger:0xadc0730 @progname=nil, @level=0, @default_formatter=#<Logger::Formatter:0xadc071c @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0xadc06a4 @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<IO:<STDOUT>>, @mutex=#<Logger::LogDevice::LogDeviceMutex:0xadc0690 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0xadc0668>>>> ruby-1.9.2-p0 > User.last User Load (0.2ms) SELECT `users`.* FROM `users` ORDER BY users.id DESC LIMIT 1 => #<User id: 15, login: "xxxxxx", name: "", email: "xx@zz.com", crypted_password: "471f98733c6d2456df58a354feddcf7af22ea78e", salt: "f03c284f91365a3eeb30a2898b79524694efdac5", remember_token: nil, remember_token_expires_at: nil, activation_code: nil, activated_at: "2011-01-07 08:00:25", status: 2, suspend_at: nil, avatar_id: nil, orgunit_id: nil, mobile_phone: nil, last_login_at: nil, language: nil, options: nil, created_at: "2011-01-07 08:00:17", updated_at: "2011-01-07 08:00:25">
另外 还可以 使用 hirb gem 来让输出格式以表格排列,个人不是太喜欢,原有的方式可以看出数据的返回格式,是集合数组 , 还是单个对象 一清二楚 。。。而hirb 就没有了
SEE:
环境:ruby 1.9.2 + rails 3.0.3 + ubuntu 10.10
params在rails中很常用,特别在表单提交的时候,params 产生的是一个Hash ,里面构造通过 form域的name构造 ,产生不同的 params 内容,今天 在看rails params 实现的时候 发现通过 attr_internal 的方法实现,params方法 的源码:
def params @_params ||= request.parameters end
发现其实是从 request 这个方法得到的,那么request方法又是怎么定义的:
attr_internal :headers, :response, :request
就是 用了 attr_internal 方法
看下 整个 metal.rb文件: here
发现了 response,headers,session(借助delegate委派) ,status,params == 都是通过 attr_internal 实现的,来看看 attr_internal 到底是何须人也 :
源码: here
class Module
# Declares an attribute reader backed by an internally-named instance variable.
def attr_internal_reader(*attrs)
attrs.each do |attr|
module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end", __FILE__, __LINE__
end
end
# Declares an attribute writer backed by an internally-named instance variable.
def attr_internal_writer(*attrs)
attrs.each do |attr|
module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end", __FILE__, __LINE__
end
end
# Declares an attribute reader and writer backed by an internally-named instance
# variable.
def attr_internal_accessor(*attrs)
attr_internal_reader(*attrs)
attr_internal_writer(*attrs)
end
alias_method :attr_internal, :attr_internal_accessor
class << self; attr_accessor :attr_internal_naming_format end
self.attr_internal_naming_format = '@_%s'
private
def attr_internal_ivar_name(attr)
Module.attr_internal_naming_format % attr
end
end
发现其实就是通过 module_eval 给 对象 添加了 settet , getter 方法而已,但是命名格式是这样的:
self.attr_internal_naming_format = '@_%s'
DEMO:
require "active_support/core_ext/module/attr_internal" class Foo attr_accessor :sex,:birthday # attr_accessor ruby里封装的method attr_internal :name,:city # attr_internal rails 封装的 def bar name # call getter method # => @_name end end f = Foo.new f.name = 'wxianfeng' p f.instance_variables # => [:@_name] p f.name # => "wxianfeng" p f # => #<Foo:0x8630e18 @_name="wxianfeng"> p f.bar # => "wxianfeng"
所以 attr_internal 和 attr_accessor 其实是 等价的,只不过 从字面意思上看是内部变量(闭包变量的写法) ,attr_internal 希望你 通过方法名来调用,不用 @_%s 这个写法 来调用
所以 其实 一般我们在 controller 用的 request 方法 其实 可以直接这样写 @_request ,
request #=> @_request params # => @_request.parameters params # => @_params headers #=> @_headers status #=> @_status . . .
但是一般 不建议这样写
还发现 这些和 http相关的东西都定义在 metal 模块, metal 是 rails 链接 rack 的中间件,源码中的解释:
ActionController::Metal provides a way to get a valid Rack application from a controller.
Rack 是一个 ruby实现的web server,封装了 http的请求和响应等,例如 rails,sinatra == 都是在 rack 基础上实现的……
有机会很有必要 深入学习下…
SEE:
http://rubyonrailswin.wordpress.com/2007/03/07/actioncontroller-and-what-the-heck-is-attr_internal/
http://www.oschina.net/p/rack









