锦囊妙计-后端篇
这两章介绍一些常见的Rails疑难杂症问题,以及常用的RubyGem套件。更多热门套件可以参考 、awesome-ruby 和 等介绍。
就三个步骤:
- Reproduce: 有特定的步骤可以重现这个 bug
- Isolate: 找出是哪一段 code 造成这个 bug
- Fix: 修好他详细可以参考 The Art of Debugging 一文
- 在 template 中使用
- 使用 Rails.logger
使用中断点 (使用指令 continue 让中断继续)byebug 详细用法请参考 https://github.com/deivid-rodriguez/byebug/blob/master/GUIDE.md
进一步找 Rails 或其他 gem 的原始码了解
- 执行
bundle open the_gem_name
会用默认的编辑器打开,可在~/.bash_profile
里面设定export EDITOR="subl"
- 执行
打开 template 和 partial 的好工具
https://github.com/rails/spring 有时候重开还是没用没有加载到修改的设定,可以试试 bin/spring stop
其他参考文章
- http://tenderlovemaking.com/2016/02/05/i-am-a-puts-debuggerer.html 一些不用 debugger 只用 puts 的除错技巧
- http://blog.motion-express.com/debugging-rails-5-skills/
- http://www.jackkinsella.ie/2014/06/06/a-comprehensive-guide-to-debugging-rails.html
如何查找 Gem 的原始码?
除了 Gem 的文件,直接查找 Gem 的原始码有时候也是除错或看用法的最好方式:
- 执行
bundle open GEM_NAME
就会用默认的编辑器打开 gem 的原始码了。 - 如果你想看 Rails 的原始码,由于 Rails 拆分成不同的 gems,所以
bundle open rails
打开来不会看到所有的 Rails 原始码。建议读者可以直接git clone git@github.com:rails/rails.git
一份官方的原始法回去即可。
Rake
用来编写任务脚本,让我们在CLI中可以执行。它的好处在于提供良好的任务编写结构,并且很方便设定各个任务的相依性,例如执行任务C前,需要先执行任务A、B。在 Rails 之中就内建了许多 rake 指令,除了你已经使用过的 rake db:migrate 之外,你可以输入 rake -T 看到所有的 rake 指令。
而要在 Rails 环境中撰写 Rake,请将附档名为 .rake 的档案放在 lib/tasks 目录下即可,例如:
透过执行 rake dev:rebuild,就会砍掉重建数据库,最后执行 rake dev:setup 建立一些假资料作为开发之用。
其他常见的使用情境包括:1. 修正上线的资料,这样部署到Production后,可以用来执行 2. 建立开发用的假资料 3. 搭配排成工具使用,例如每天凌晨三点寄出通知信、每周一产生报表等等
更多介绍可以参考 http://jasonseifer.com/2010/04/06/rake-tutorial 这篇文章。
分页
- 目前比较流行用这个
- will_paginate 比较老的专案会用这个
档案上传
- 是目前使用上最为方便的档案上传 plugin。
- CarrierWave 写起来比较繁琐但设计比较严谨
范例 source code
假设字段叫做 attachment 的话,改成以下宣告:
has_attached_file :attachment
do_not_validate_attachment_file_type :attachment
设定档处理
在整合第三方应用时,第三方的 API Key 和 token 等等,我们不希望 hard-code 在程式码里面,一来是因为我们可能不想把这些敏感的 keys commit 进去版本控制系统。二来是因为将来布署的时候,在 staging 和 production 不同环境下,这些 key 都会不一样,我们希望容易抽换。
因此,有几种作法和考量:
使用 YAML 格式作为设定档放到 config 目录下
要注意
- YAML 会区分数字和字串,例如
01234
会看成1234
,如果要确保被看成字串,请加上引号,例如 - 读出来的 Hash 是用字串 key,不是 symbol key。例如是
fb_config["app_id"]
而不是fb_config[:app_id]
- 如果要通吃,可以用
symbolize_keys
这个方法,例如fb_config = fb_config = Rails.application.config_for(:facebook).symbolize_keys
。这样用字串或 symbol 都可以。
如果不要 commit,请加进 .gitignore
因为设定档的东西不同开发者可能不一样、而且可能包括敏感资料,因此如果不要 commit,就列在 .gitignore 里面。
并且依照开发者惯例,我们会产生一个 xxx.yml.example 档案当作设定范例给同事参考。例如: 放 AWS key 的 s3.yml.example
、放 email 设定的 email.yml.example
但是如果该设定档的内容机密层级低、专案是放在 private repository 的话(各位的练习作业和期末专案是放在 public repository),而且每个开发者的设定档都长得一样,那么 commit 出去也无妨,大家开发会比较方便。例如config/database.yml
地的数据库帐号密码,大家可以讲好都设成一样帐号root
、密码留空即可。
除了写在 YAML 档案中,这些 token 也可以写进config/secret.yml
,例如以下的设定,用Rails.application.secrets.batchbook_api_key
就可以拿到值了。
环境变量作法
也有一些人不喜欢用 yaml 加载,而是用环境变量。请参考 这篇文章的作法。
通常是对 Linux 环境比较熟悉的同学,比较喜欢用这种作法。Heroku 也有专文 The twelve-factor app 推崇这种作法。
ActiveReord: 加强搜寻
- 可以很快的针对ActiveRecord做出排序和复杂的条件搜寻。不过 ransack 并不太考虑效能问题,特别是文字模糊搜寻,这部份网站长大后会改用全文搜寻引擎,例如 ElasticSearch
搭配 jQuery UI Sortable 就可以做出拖拉排序,可以参考这篇文章。
Model 设计:
UI 设计可用 jQuery UI Sortable:
Example Code:
ActiveReord: Self-referential Relationships
1-to-many tree 树状结构 (parent and children)
many-to-many
- http://railscasts.com/episodes/163-self-referential-association
- Friendship 朋友关系范例:
ActiveReord: Tagging 标籤
可以自己写,也是多对多模型,搭配虚拟属性(Virtual Attribute)的设计来达到使用者可以输入任意的 tag nameTag model: name, taggings_countTagging: tag_id, {target_model}_id
ActiveReord: Soft Deletion 和版本控制,编辑和删除后还可以留下纪录和还原,
- paper_trail 另开一个 versions table 完整纪录
- 加一个字段标记被删除。不建议用这种方式,因为会让数据库的 unique key 检查出问题。
- audited
ActiveReord: 有限状态机
适合用来设计比较复杂的 model 流程状态
ActiveReord: 资料表注解
会帮你在model code上面注解加上所有资料表的字段
API 串接:处理 HTTP
Ruby 内建的 Net::HTTP 设计的不是很好用,因此大多数人改用其他 API 比较好用的函式库,例如:
范例 Source Code
安装 gem 'rest-client'
- 抓 Ubike 资料
- 抓 Facebook 个人资料(需透过 token) https://github.com/ihower/rails-exercise-ac8/commit/1c1746c04b3eb08864de1512e7f7abf542aae381
- Github API:
- 政府开放资料 http://data.gov.tw/
- g0v 开放资料
- SheetHub http://sheethub.com
- 资策会 Social Event Radar
- 台北市政府开放资料 http://data.taipei/
- YouBike台北市公共自行车即时资讯: 和 字段说明文件
- 台北市政府 食材登录平台
- 台北市政府 交通即时资料 开放资料专区 https://taipeicity.github.io/traffic_realtime/
- 可以产生 PDF,支援 Unicode。
- PDFKit 则是另一个有趣的产生方式,透过 HTML/CSS 转 PDF。
- 是一套商用方案,将 HTML/CSS 转 PDF
CSV
Ruby就有内建这个函式库了,只需要require "csv"
即可使用。
YAML
Rails 的数据库设定档 database.yml 是用一种叫 : YAML Ain’t Markup Language 的格式所撰写,档案打开来,看起来就像一般的 plain 设定档,非常容易修改。
YAML 的设计首要目标就是要让使用者容易看懂,可以和 script 语言搭配良好。用途有 资料序列化 data serialization、设定档 configuration settings、log files、Internet messaging、filtering 等。网站上已知有支援的 script 语言有 Python,Ruby,Java,PHP,Perl,Javascript 等。
ps2 = YAML.load_file(‘example.yaml’)
ps2.each do |it|
puts it.inspect
end
JSON
Rails 内建就有 ,用法如下:
yajl-ruby 则是一套底层用C,比较快很多的 JSON parser,建议可以让Rails底层改用这套函式库,请在Gemfile
档案中加入
gem 'yajl-ruby', :require => 'yajl'
XML
Rails 内建使用 Ruby 的 XML 函式库
Nokogiri 是一套基于 的函式库,效能较佳。可参考 Getting Started with Nokogiri 一文介绍用法。
如果要替换 Rails 内建的 XML 函式库,请在Gemfile
档案中加入
排程工具
如果您有周期性的任务需要执行,除了可以透过Linux的crontab设定去执行rake脚本。例如输入crontab -e加入:
0 2 * * * cd /home/your_project/current/ && RAILS_ENV=production /usr/local/bin/rake cron:daily
就是每天凌晨两点执行rake cron:daily这个任务。
或是你可以安装这个 gem,就可以用Ruby的语法来定义周期性的任务,可以很方便的设定服务器上的cron排程。
自动备份
可以搭配 whenever 就可以定期备份了
小版号的升级,通常透过以下步骤即可完成:
- 修改
Gemfile
的Rails版本:gem 'rails', '3.1.1'
- 执行
bundle update
- 执行 会尝试更新Rails自己产生的档案,例如config/boot.rb,请一一手动检查。