欢迎转载,请支持原创,保留原文链接:blog.ilibrary.me

转义

%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 数据类型

  1. :binary,
  2. :boolean,
  3. :date,
  4. :datetime,
  5. :decimal,
  6. :float,
  7. :integer,
  8. :string,
  9. :text,
  10. :time,
  11. :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

Ruby元编程游戏

代码内嵌数据

读取每一行数据

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

DATA和__END___讲代码和数据混合

双星 **

双星在 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}]

参考

  1. how-do-you-do-relative-time-in-rails
  2. 来自37signals的3个Rails console技巧