- 锦囊妙计-后端篇
- 锦囊妙计-后端篇
- 如何除错 Debug?
- 如何查找 Gem 的原始码?
- Rake
- 分页
- 档案上传
- 设定档处理
- ActiveReord: 加强搜寻
- ActiveReord: 列表结构(自订排列顺序)
- ActiveReord: Self-referential Relationships
- ActiveReord: Tagging 标籤
- ActiveReord: Soft Deletion 和版本控制,编辑和删除后还可以留下纪录和还原,
- ActiveReord: 有限状态机
- ActiveReord: 资料表注解
- API 串接:处理 HTTP
- CSV
- YAML
- JSON
- XML
- 排程工具
- 自动备份
- 升级Rails
- 其他
锦囊妙计-后端篇
锦囊妙计-后端篇
When you choose a language, you’re choosing more than a set of technical trade-offs—you’re choosing a community. - Joshua Bloch
这两章介绍一些常见的 Rails 疑难杂症问题,以及常用的 RubyGem 套件。更多热门套件可以参考 The Ruby Toolbox、awesome-ruby 和 awesome-rails-gem 等介绍。
如何除错 Debug?
就三个步骤:
- Reproduce: 有特定的步骤可以重现这个 bug
- Isolate: 找出是哪一段 code 造成这个 bug
- Fix: 修好他详细可以参考 The Art of Debugging 一文
Debug 方法
- 在 template 中使用
<%= debug your_variable %> - 使用 Rails.logger
- 使用 web console 发生例外的时候会出现,或是自己放 console 到程式里面
-
使用中断点 byebug (使用指令 continue 让中断继续)byebug 详细用法请参考 <https://github.com/deivid-rodriguez/byebug/blob/master/GUIDE.md>
-
进一步找 Rails 或其他 gem 的原始码了解
- 执行
bundle open the_gem_name会用默认的编辑器打开,可在~/.bash_profile里面设定export EDITOR="subl" - <https://github.com/brentd/xray-rails> 打开 template 和 partial 的好工具
- 执行
-
<https://github.com/rails/spring> 有时候重开还是没用没有加载到修改的设定,可以试试 bin/spring stop
其他参考文章
- <https://speakerdeck.com/igaiga/rubyconftaiwan2015>
- <http://tenderlovemaking.com/2016/02/05/i-am-a-puts-debuggerer.html> 一些不用 debugger 只用 puts 的除错技巧
- <http://rails.ruby.tw/debugging_rails_applications.html>
- <http://blog.motion-express.com/debugging-rails-5-skills/>
- <http://www.rubyonrails365.com/7-must-have-gems-to-install-on-any-project>
- <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
Rake 用来编写任务脚本,让我们在CLI中可以执行。它的好处在于提供良好的任务编写结构,并且很方便设定各个任务的相依性,例如执行任务C前,需要先执行任务A、B。在 Rails 之中就内建了许多 rake 指令,除了你已经使用过的 rake db:migrate 之外,你可以输入 rake -T 看到所有的 rake 指令。
而要在 Rails 环境中撰写 Rake,请将附档名为 .rake 的档案放在 lib/tasks 目录下即可,例如:
## /lib/tasks/dev.rake
namespace :dev do
desc "Rebuild system"
task :rebuild => ["db:drop", "db:setup", :fake]
task :fake => :environment do
puts "Create fake data for development"
u = User.new( :login => "root", :password => "password", :email => "root@example.com", :name => "管理员")
u.save!
end
end
透过执行 rake dev:rebuild,就会砍掉重建数据库,最后执行 rake dev:setup 建立一些假资料作为开发之用。
推荐 <https://github.com/stympy/faker> 这个 gem 可以产生各种假资料
其他常见的使用情境包括:1. 修正上线的资料,这样部署到 Production 后,可以用来执行 2. 建立开发用的假资料 3. 搭配排成工具使用,例如每天凌晨三点寄出通知信、每周一产生报表等等
更多介绍可以参考 <http://jasonseifer.com/2010/04/06/rake-tutorial> 这篇文章。
分页
- kaminari 目前比较流行用这个
- will_paginate 比较老的专案会用这个
档案上传
- Paperclip 是目前使用上最为方便的档案上传 plugin。
- CarrierWave 写起来比较繁琐但设计比较严谨
范例 source code
- <https://github.com/ihower/rails-exercise-ac4/commit/3fca6237babd4f462924d9c12696a8f17f0ef32c>
- <https://github.com/ihower/rails-exercise-ac6/commit/7de1031f64807de69bf83f32e46ae0ddab4f9414>
paperclip 如何上传任意格式的档案?
假设字段叫做 attachment 的话,改成以下宣告:
has_attached_file :attachment
do_not_validate_attachment_file_type :attachment
设定档处理
在整合第三方应用时,第三方的 API Key 和 token 等等,我们不希望 hard-code 在程式码里面,一来是因为我们可能不想把这些敏感的 keys commit 进去版本控制系统。二来是因为将来布署的时候,在 staging 和 production 不同环境下,这些 key 都会不一样,我们希望容易抽换。
因此,有几种作法和考量:
使用 YAML 格式作为设定档放到 config 目录下
fb_config = YAML.load(File.read("#{Rails.root}/config/facebook.yml"))[Rails.env]或 fb_config = Rails.application.config_for(:facebook)
要注意
- YAML 会区分数字和字串,例如
01234会看成1234,如果要确保被看成字串,请加上引号,例如"01234" - 读出来的 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
一些 commit 也无妨的情况
但是如果该设定档的内容机密层级低、专案是放在 private repository 的话(各位的练习作业和期末专案是放在 public repository),而且每个开发者的设定档都长得一样,那么 commit 出去也无妨,大家开发会比较方便。例如config/database.yml地的数据库帐号密码,大家可以讲好都设成一样帐号root、密码留空即可。
除了写在 YAML 档案中,这些 token 也可以写进config/secret.yml,例如以下的设定,用Rails.application.secrets.batchbook_api_key就可以拿到值了。
development:
secret_key_base: XXXXXX
batchbook_api_key: YYYYYYYY
环境变量作法
也有一些人不喜欢用 yaml 加载,而是用环境变量。请参考 The Rubyist’s Guide to Environment Variables 这篇文章的作法。
通常是对 Linux 环境比较熟悉的同学,比较喜欢用这种作法。Heroku 也有专文 The twelve-factor app 推崇这种作法。
ActiveReord: 加强搜寻
- Ransack可以很快的针对 ActiveRecord 做出排序和复杂的条件搜寻。不过 ransack 并不太考虑效能问题,特别是文字模糊搜寻,这部份网站长大后会改用全文搜寻引擎,例如 ElasticSearch
ActiveReord: 列表结构(自订排列顺序)
搭配 jQuery UI Sortable 就可以做出拖拉排序,可以参考 Sortable Lists这篇文章。
Model 设计:
- <https://github.com/swanandp/acts_as_list>
- 或 <https://github.com/mixonic/ranked-model>
UI 设计可用 jQuery UI Sortable:
- <https://github.com/joliss/jquery-ui-rails>
- <http://api.jqueryui.com/sortable/#event-update>
- <http://railscasts.com/episodes/147-sortable-lists-revised>
Example Code: <https://github.com/ihower/rails-exercise-ac5/blob/master/app/views/events/index.html.erb>
ActiveReord: Self-referential Relationships
1-to-many tree 树状结构 (parent and children)
- 树状结构 比较 awesome_nested_set、ancestry 和 closure_tree
- <https://github.com/amerine/acts_as_tree>
- <https://github.com/stefankroes/ancestry>
- <https://github.com/collectiveidea/awesome_nested_set>
- <https://github.com/mceachen/closure_tree>
- 应用范例: <http://railscasts.com/episodes/162-tree-based-navigation?view=asciicast>
many-to-many
- <http://railscasts.com/episodes/163-self-referential-association>
- Friendship 朋友关系范例: <https://github.com/ihower/social-exercise-ac3/blob/master/app/models/user.rb>
ActiveReord: Tagging 标籤
可以自己写,也是多对多模型,搭配虚拟属性(Virtual Attribute)的设计来达到使用者可以输入任意的 tag nameTag model: name, taggings_countTagging: tag_id, {target_model}_id
- Tagging 教学文 <http://www.sitepoint.com/tagging-scratch-rails/>
- acts-as-taggable-on
- <http://easyactiverecord.com/blog/2014/10/21/tagging-your-content-using-the-acts-as-taggable-on-gem/>
ActiveReord: Soft Deletion 和版本控制,编辑和删除后还可以留下纪录和还原,
- paper_trail 另开一个 versions table 完整纪录
- paranoia 加一个字段标记被删除。不建议用这种方式,因为会让数据库的 unique key 检查出问题。
- audited
ActiveReord: 有限状态机
适合用来设计比较复杂的 model 流程状态
ActiveReord: 资料表注解
会帮你在 model code 上面注解加上所有资料表的字段
根据 ActiveRecord 的关联自动产生漂亮的 Entity-Relationship Diagrams
API 串接:处理 HTTP
Ruby 内建的 Net::HTTP 设计的不是很好用,因此大多数人改用其他 API 比较好用的函式库,例如:
- <https://github.com/rest-client/rest-client>
- <https://github.com/lostisland/faraday>
范例 Source Code
安装 gem 'rest-client'
- 抓 Ubike 资料 <https://github.com/ihower/rails-exercise-ac8/commit/2eed28e94fc60aa7b7cc11cce531321e86254b0d#diff-d36dd0926c5b89774b950af54144b8b2R3>
- 抓 Facebook 个人资料(需透过 token) <https://github.com/ihower/rails-exercise-ac8/commit/1c1746c04b3eb08864de1512e7f7abf542aae381>
一些 API 资料来源
- Github API: <https://api.github.com/users/ihower>
- 政府开放资料 <http://data.gov.tw/>
- g0v 开放资料 <http://data.g0v.tw/>
- SheetHub <http://sheethub.com>
- 资策会 Social Event Radar <http://api.ser.ideas.iii.org.tw/docs/#!/fb_fanpage_search>
- 台北市政府开放资料 <http://data.taipei/>
- YouBike台北市公共自行车即时资讯: API 端点 URL 和 字段说明文件
- 台北市政府 食材登录平台 <https://taipeicity.github.io/foodtracer/>
- 台北市政府 交通即时资料 开放资料专区 <https://taipeicity.github.io/traffic_realtime/>
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 等。
require ‘yaml’
ps2 = YAML.load_file(‘example.yaml’)
ps2.each do |it|
puts it.inspect
end
JSON
Rails 内建就有 ActiveSupport JSON,用法如下:
ActiveSupport::JSON.encode( [ {:a => 1 , :b => 2 } , "c", "d" ] )
=> "[{\"a\":1,\"b\":2},\"c\",\"d\"]"
ActiveSupport::JSON.decode( "[{\"a\":1,\"b\":2},\"c\",\"d\"]" )
=> [{"a"=>1, "b"=>2}, "c", "d"]
yajl-ruby 则是一套底层用C,比较快很多的 JSON parser,建议可以让 Rails 底层改用这套函式库,请在Gemfile档案中加入
gem 'yajl-ruby', :require => 'yajl'
XML
Rails 内建使用 Ruby 的 XML 函式库 Builder
Nokogiri 是一套基于 libxml2 的函式库,效能较佳。可参考 Getting Started with Nokogiri 一文介绍用法。
如果要替换 Rails 内建的 XML 函式库,请在Gemfile档案中加入
gem 'nokogiri'
有些函式库为了执行效率,底层会改用 C 的函式库,适合于正式上线环境,缺点是需要编译,在一些特殊环境可能无法运作,例如最新版的 Nokogiri 就不支援 Windows 了。而纯 Ruby 实作的版本就没有这个问题。
排程工具
如果您有周期性的任务需要执行,除了可以透过 Linux 的 crontab 设定去执行 rake 脚本。例如输入 crontab -e 加入:
0 2 * * * cd /home/your_project/current/ && RAILS_ENV=production /usr/local/bin/rake cron:daily
就是每天凌晨两点执行 rake cron:daily 这个任务。
或是你可以安装 whenever 这个 gem,就可以用 Ruby 的语法来定义周期性的任务,可以很方便的设定服务器上的 cron 排程。
自动备份
- <https://github.com/meskyanichi/backup>
可以搭配 whenever 就可以定期备份了
升级Rails
小版号的升级,通常透过以下步骤即可完成:
- 修改
Gemfile的 Rails 版本:gem 'rails', '3.1.1' - 执行
bundle update - 执行
rake rails:update会尝试更新 Rails 自己产生的档案,例如 config/boot.rb ,请一一手动检查。
升级前,也请参阅官方公告的升级注意事项。
其他
- <http://asciicasts.com/episodes/255-undo-with-papertrail>
- <http://intridea.com/2011/5/13/rails3-gems>
- <http://erik.debill.org/2011/12/04/rake-for-rails-developers>
