Rails常用方法和技巧
转义
%Q
用于替代双引号的字符串
>> %Q(Joe said: "Frank said: "#{what_frank_said}"")
=> "Joe said: "Frank said: "Hello!"""
(…)也可用其他非数字字母的符号或成对的符号代替, 诸如[…], !…!, +…+,{…}, <…>等. 以下写法全部与上面等效:
%Q!Joe said: "Frank said: "#{what_frank_said}""!
%Q[Joe said: "Frank said: "#{what_frank_said}""]
%Q+Joe said: "Frank said: "#{what_frank_said}""+
除此之外还可以省略Q写作:
%/Joe said: "Frank said: "#{what_frank_said}""/
"Joe said: "Frank said: "Hello!"""
%q
与 %Q类似, 但是表示的是单引号字符串.
%W
与%Q类似,表示其中的元素被双引号括起的数组
>> %W(#{foo} Bar Bar\ with\ space)
=> ["Foo", "Bar", "Bar with space"]
%x
执行一段脚本并发挥标准输出内容
>> %x(echo foo:#{foo})
=> "foo:Foo\n"
%r
用于正则表达式
>> %r(/home/#{foo})
=> "/\\/home\\/Foo/"
%s
用于表示symbol,但是不会对其中表达式等内容进行转化
>> %s(foo)
=> :foo
>> %s(foo bar)
=> :"foo bar"
>> %s(#{foo} bar)
=> :"\#{foo} bar"
%i
Ruby 2.0 之后引入的语法, 用于生成一个symbol数组
> %i(a b c)
=> [:a, :b, :c]
时间
Time.now.yesterday
Time.now.ago(2.days).end_of_day
Time.now.next_month.beginning_of_month
30.seconds.ago
1.week.ago
1.weeks.ago #没有单复数的区别
2.week.ago
2.weeks.ago
1.day.ago
1.days.ago
2.day.ago
2.days.ago
Time.now - 2.days
链接
link_to "链接文本", {action: :index, controller: :home, }
ActiveRecord查询
Model.distinct.pluck(:name) # 查询所有不重复的名字
按时间范围查询
User.where(date => 30.days.ago..Time.now)
User.where('created_at < :sixty_days_ago', sixty_days_ago: Time.now - 60.days)
User.where(created_at: Time.current.all_week) # all_day, all_week, all_quarter, all_year
统计
{a: 1, b: 2}.values.sum # Hash计算所有value的和
{a: 1, b: 2}.sort_by { |key, value| value}
Rake命令
rails的优势之一是有一套很强大的自动化工具,辅助你去完成一些模板生成(rails命令, 5.0以后rake命令可以直接用rails命令来执行),数据库管理,数据迁移,问题诊断等。 熟练掌握rake能把你从简单重复劳动中解放出来,集中精力去思考一些业务相关的问题。
rake -T # 显示所有的rake tasks
rails -h # 查看所有rails命令,包括rake命令
rake routes # 查看所有路由, 路由里面的prefix就是我们在link_to里面用到的路径参数来源
rake db:create
rake db:drop
Rails Console
Rails console是非常重要的一个调试入口,对问题诊断,功能开发,测试都非常有帮助。熟练掌握rails console的技能对开发能起到事半功倍的作用。
启动console
rails c #进入console
rails c test #进入test环境
rails c --sandbox # 进入沙盒环境,退出的时候会回滚数据库
cd 和ls
cd app # 进入app对象
ls #查看app所有方法和变量
cd .. #退出当前对象
exit #退出当前对象
查看上一个exception
[8] pry(main)> 1/0
ZeroDivisionError: divided by 0
from (pry):8:in `/'
[9] pry(main)> _ex_
=> #<ZeroDivisionError: divided by 0>
基础操作
reload! # 热重启rails console
Movie.wh<tab> # 自动补全命令
movies = _ # 下划线代表上一个命令的返回值
"".methods.grep(/case/).sort # 查找方法
ClassName.instance_methods # 查找所有实例方法
Dir["your-directory/**/*"].length # 数有多少个文件
调试请求
app.get('/')
response = app.response
response.cookies
>> app.session[:user_id]
=> 7
app.topics_path
app.get(app.root_path)
>> app.movies_path
=> "/movies"
>> app.movie_path(Movie.first)
=> "/movies/1"
ApplicationController.allow_forgery_protection = false # disable CSRF token in console
app.post "/users/sign_in", email: "foo@bar.com", password: "foobar"
调试helper 方法
irb > helper.link_to("Ruby China", "http://ruby-china.org")
=> "<a href=\"http://ruby-china.org\">Ruby China</a>"
irb > helper.truncate("Here is Ruby China.", length: 15)
=> "Here is Ruby..."
>> helper.pluralize(3, 'mouse')
=> "3 mice"
>> helper.number_to_currency(1.50)
=> "$1.50"
>> helper.truncate("Iron Man", length: 7)
=> "Iron..."
>> helper.title_tag(Movie.first)
=> "<title>Flix - Iron Man</title>"
>> helper.poster_image_for(Movie.first)
=> "<img alt=\"Ironman\" src=\"/assets/ironman.png\" />"
使用source_location方法查看方法在哪里定义的
irb >Topic.instance_method(:destroy).source_location
=> ["/Users/jason/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-2.4.8/lib/mongoid/persistence.rb", 30]
irb >Topic.method(:destroy_all).source_location
=> ["/Users/jason/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-2.4.8/lib/mongoid/persistence.rb", 239]
进入对象
>> irb app
>> get "/movies"
=> 200
>> get "/users/1"
=> 302
app object
app是rails console里面内置的变量.可以用于调试application的功能,具体调试方法见上面章节。app对象有以下方法可以供使用。
app
app.host
app.class
app.methods
app.method(:get).source_location
app.main_app
app.main_app.methods
app.root_path
app.root_url
app.user_path(3, sort: "yo yo") #=> "/users/3?sort=yo+yo"
app.name_path
app.project_path(Project.first)
app.get "/users/1"
app.response
app.response.header
app.response.body
app.response.redirect_url
app.session[:user_id]
app.cookies
app.flash
scaffold
rails destroy scaffold product
rails g scaffold product parent:references
rails destroy scaffold product # destroy scaffold
rails destroy model profile #destroy model
生成一个干净的controller
rails generate controller home index --no-helper --no-assets --no-controller-specs --no-view-specs
在model存在的情况下生产controller、view和tests
rails generate scaffold_controller user
active record 数据类型
:binary
,:boolean
,:date
,:datetime
,:decimal
,:float
,:integer
,:string
,:text
,:time
,:timestamp
rails status code
查看所有status code
Rack::Utils::HTTP_STATUS_CODES
{100=>"Continue",
101=>"Switching Protocols",
102=>"Processing",
200=>"OK",
201=>"Created",
202=>"Accepted",
203=>"Non-Authoritative Information",
204=>"No Content",
205=>"Reset Content",
206=>"Partial Content",
207=>"Multi-Status",
208=>"Already Reported",
226=>"IM Used",
300=>"Multiple Choices",
301=>"Moved Permanently",
302=>"Found",
303=>"See Other",
304=>"Not Modified",
305=>"Use Proxy",
307=>"Temporary Redirect",
308=>"Permanent Redirect",
400=>"Bad Request",
401=>"Unauthorized",
402=>"Payment Required",
403=>"Forbidden",
404=>"Not Found",
405=>"Method Not Allowed",
406=>"Not Acceptable",
407=>"Proxy Authentication Required",
408=>"Request Timeout",
409=>"Conflict",
410=>"Gone",
411=>"Length Required",
412=>"Precondition Failed",
413=>"Payload Too Large",
414=>"URI Too Long",
415=>"Unsupported Media Type",
416=>"Range Not Satisfiable",
417=>"Expectation Failed",
421=>"Misdirected Request",
422=>"Unprocessable Entity",
423=>"Locked",
424=>"Failed Dependency",
426=>"Upgrade Required",
428=>"Precondition Required",
429=>"Too Many Requests",
431=>"Request Header Fields Too Large",
451=>"Unavailable for Legal Reasons",
500=>"Internal Server Error",
501=>"Not Implemented",
502=>"Bad Gateway",
503=>"Service Unavailable",
504=>"Gateway Timeout",
505=>"HTTP Version Not Supported",
506=>"Variant Also Negotiates",
507=>"Insufficient Storage",
508=>"Loop Detected",
510=>"Not Extended",
511=>"Network Authentication Required"}
发送status code
head :ok
head 200
head :length_required
head 411
调试/深入理解ruby
利用Ripper分析token, 词法分析
require 'ripper'
require 'pp'
code = <<STR
10.times do |n|
puts n
end
STR
puts code
pp Ripper.lex(code) # pp is pretty print
pp Ripper.sexp(code) # ruby代码解析过程
利用 -y
选项调试语法分析(规约流程)
ruby -y simple.rb
ruby -y -e 'puts 1'
ruby --dump -e parsetree # 打印AST树
pp Ripper.sexp(code) # ruby代码解析过程
YARV 调试
puts RubyVM::InstructionSequence.compile(code).disasm
irb调试指令
Object.ancestors
q.method(:page).source_location # 查看某方法所在的地方
method(:test).owner #查看方法归属于谁
method(:print).owner
method(:eval).owner
method(:method).owner
self.binding #获取上下文对象
10_000_000 #1千万的逗号式写法
self.class.instance_methods false # 查看非继承的实例方法
Object.constants #查看所有常量
obj.instance_variable_set("@x", 3) #设置实例变量的值
m.instance_eval { @zen } # 访问实例变量, 更多的元编程代码请看 http://rubymonk.com/learning/books/5-metaprogramming-ruby-ascent/chapters/24-eval/lessons/67-instance-eval
MyClass.instance_eval("def zen;;end") # 定义类方法, MyClass.zen
MyClass.class_eval("def zen;;end") # 定义实例方法,MyClass.new.zen
MyClass.new.instance_eval("def zen;;end").zen # 定义singleton方法, 只能当前实例调用
# 也可以用block
MyClass.instance_eval {def zen;;end}
gem dependency -R kaminari # 查看kaminari相关的依赖和被依赖关系
gem dependency --reverse-dependencies will_paginate
代码内嵌数据
读取每一行数据
DATA.each_line do |line|
puts line
end
__END__
Doom
Quake
Diablo
源代码里面内嵌模板做渲染
require 'erb'
time = Time.now
renderer = ERB.new(DATA.read)
puts renderer.result()
__END__
The current time is <%= time %>.
通过rewind
方法读取整个源文件.
DATA.rewind
puts DATA.read # prints the entire source file
__END__
meh
双星 **
双星在 Ruby 中是一个小魔法,来看看下面的方法:
def my_method(a, *b, **c)
end
a 是一个常规的参数,b 将会得到第一个参数后面的所有参数并把他们放入一个数组中, **c 将会得到传人方法的任何格式为 key: value 的参数。
来看看下面的例子: 一个参数
my_method(1)
# => [1, [], {}]
超过一个参数
my_method(1, 2, 3, 4)
# => [1, [2, 3, 4], {}]
超过一个参数 + hash-style 参数
my_method(1, 2, 3, 4, a: 1, b: 2)
# => [1, [2, 3, 4], {:a => 1, :b => 2}]