Change Box

生命成为一朵烟花最好,升起在旷野的夜空,明亮而狂野,盲目而绚烂。然后沉寂,消失。 如此干脆。

42个Rails Tips

| Comments

原文: From RailsConf 2012 - 10 Things You Didn’t Know Rails Could do

本文适用Rails 版本 3.2.3


Tip 1 : Run From A Single File 可以单文件运行

source

http://thesmallestrailsapp.com/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
%w(action_controller/railtie coderay).map &method(:require)

run TheSmallestRailsApp ||= Class.new(Rails::Application) {
  config.secret_token = routes.append { root to: 'hello#world' }.inspect
  initialize!
}

class HelloController < ActionController::Base
  def world
    render inline: "
      <!DOCTYPE html>
      <title>The Smallest Rails App</title>
      <h3>I am the smallest rails app!</h3>
      <p>Here is my source code:</p>
      #{CodeRay.scan_file(__FILE__, :ruby).div(line_numbers: :table)}
      <a href='https://github.com/artemave/thesmallestrailsapp.com'>Make me smaller</a>
    "
  end
end

Tip 2: Remind you of things 提醒功能,TODO list

users_controller.rb
1
2
3
   class UsersController < ApplicationController
     # TODO:  Make it possible to create new users.
   end
user.rb
1
2
3
4
  class User < ActiveRecord::Base
    # FIXME: Should token really  be accessible?
    attr_accessible :bil, :email, :name, :token
  end
index.html.erb
1
2
  <%# OPTIMIZE: Paginate this listing. %>
  <%= render Article.all %>

a. 执行命令:

$ rake notes

会输出如下结果:

app/controllers/users_controller.rb:
  * [ 2] [TODO] Make it possible to create new users.

app/models/user.rb:
  * [ 2] [FIXME] Should token really be accessible?

app/views/articles/index.html.erb:
  * [ 1] [OPTIMIZE] Paginate this listing.

b. 执行命令:

$ rake notes:todo

会只输出和TODO相关的:

app/controllers/users_controller.rb:
  * [ 2] Make it possible to create new users.

c. 执行命令:

$ rake notes:fixme

会只输出和FIXME相关的:

app/models/user.rb:
  * [ 2] Should token really be accessible?

d. 还可以自定义:

article.rb
1
2
3
4
5
  class Article < ActiveRecord::Base
    belongs_to :user
    attr_accessible :body, :subject
    # JEG2: Add that code from your blog here.
  end

执行命令:

$ rake notes:custom ANNOTATION=JEG2

会输出结果:

app/models/article.rb:
  * [ 4]Add that code from your blog here.

e. 在TextMate里面你还可以使用TODO 插件

Tip 3: Sandbox your Console 使用沙箱控制台

执行命令:

rails c --sandbox

使用这个控制台,里面任何的改变都会在你退出之后自动回滚到你未修改前的数据。

执行命令:

rails r 'p [Article, Comment, User].map(&:count)'

rails r 会执行引号里的代码。

Tip 4: Run Helper Methods in the Console 在控制台运行Helper方法

in the Console
1
2
3
4
5
6
   $ rails c
   Loading development environment (Rails 3.2.3)
   >> helper.number_to_currency(100)
   => "$100.00"
   >> helper.time_ago_in_words(3.days.ago)
   => "3 days"

Tip 5: Use Non-WEBrick Servers in Development 在开发中使用非Webrick服务器

Gemfile
1
2
3
4
5
6
   source "https://rubygems.org"
   # ...

   group :development do
     gem 'thin'
   end

执行命令:

% rails s thin

Tip 6: Allow you to tab into its configuration 自定义配置

lib/custom/railtie.rb
1
2
3
4
5
   module Custom
     class Railtie < Rails::Railtie
       config.custom = ActiveSupport::OrderedOptions.new
     end
   end
config/application.rb
1
2
3
4
5
6
7
8
   require_relative "../lib/custom/railtie"

   module Blog
     class Application < Rails::Application
       # ...
       config.custom.setting = 42
     end
   end

Tip 7: Keep you Entertained

RubyDramas

Tip 8: UnderStand Shorthand Migrations 理解便携的迁移文件

$ rails g resources user name:string email:string token:string bio:text

可以简写为:

$ rails g resources user name email token:string{6} bio:text

生成migrations:

Migrations
1
2
3
4
5
6
7
8
9
10
11
   class CreateUsers < ActiveRecord::Migration
     def change
       create_table :users do |t|
         t.string :name
         t.string :email
         t.string :token, :limit => 6
         t.text :bio
         t.timestamps
       end
     end
   end

Tip 9: Add Indexes to Migrations 增加索引

$rails g resource user name:index email:uniq token:string{6} bio:text

生成:

Migrations
1
2
3
4
5
6
7
8
9
10
11
12
13
   class CreateUsers < ActiveRecord::Migration
     def change
       create_table :users do |t|
         t.string :name
         t.string :email
         t.string :token, :limit => 6
         t.text :bio
         t.timestamps
       end
       add_index :users, :name
       add_index :users, :email, :unique => true
     end
   end

Tip 10: Add Associations to a Migration 增加关联关系到迁移文件

$rails g resource article user:references subject body:text

生成Migrations文件和model文件:

Migrations
1
2
3
4
5
6
7
8
9
10
11
   class CreateArticles < ActiveRecord::Migration
     def change
       create_table :articles do |t|
         t.references :user
         t.string :subject
         t.text :body
         t.timestamps
       end
       add_index :articles, :user_id
     end
   end
models/article.rb
1
2
3
4
   class Article < ActiveRecord::Base
     belongs_to :user
     attr_accessible :body, :subject
   end

还可以使用命令:

rails g resource comment user:blongs_to article:belongs_to body:text

会生成和user、article相关联的model和migration文件。

Tip 11: Show you the status of the database 显示数据库状态

使用命令:

 $ rake db:migrate:status

输出:

 database: db/development.sqlite3

 status   Migration ID    Migration Name
 ---------------------------------------
   up     20120414155612  Create users
   up     20120414160528  Create articles
  down    20120414161355  Create comments

Tip 12: Import your CSV Data

csv data:

Name,Email
James,james@example.com
Dana,dana@example.com
Summer,summer@example.com

导入代码:

import csv
1
2
3
4
5
6
7
8
9
10
11
12
13
   require 'csv'

   namespace :users do
     desc "Import users from a CSV file"
     task :import => :environment do
       path = ENV.fetch("CSV_FILE") {
         File.join(File.dirname(__FILE__), *%w[.. .. db data users.csv])
       }
       CSV.foreach(path, headers: true, header_converters: :symbol) do |row|
         User.create(row.to_hash)
       end
     end
   end

注意:

  • headers: true, header_converters: :symbol 这个配置项
  • row.to_hash

Tip 13 : Store CSV in Your Database 在数据库里存储CSV

store csv
1
2
3
4
5
6
7
8
9
10
11
12
13
  class Article <  ActiveRecord::Base
    require 'csv'
    module CSVSerializer
      module_function
      def load(field); field.to_s.parse_csv; end
      def dump(object); Array(object).to_csv; end
    end
    serialize :categories, CSVSerializer

    # ...

    attr_accessible :body, :subject, :categories
  end

Tip 14: “Pluck” Fields out of your database 从数据库‘Pluck’字段。

$ rails c
loading development environment(Rails 3.2.3)

>> User.select(:email).map(&:email)
  User Load(0.1ms) SELECT email FROM "users"
=> ["james@example.com", "dana@example.com", "summer@example.com"]
>> User.pluck(:email)
   (0.2ms) SELECT email FROM "users"
=> ["james@example.com", "dana@example.com", "summer@example.com"]
>> User.uniq.pluck(:email)
   (0.2ms) SELECT DISTINCT email FROM "users"
=> ["james@example.com", "dana@example.com", "summer@example.com"]

Tip 15: Count Records in Groups

$ rails g resource event article:belongs_to trigger

进控制台

$ rails c

>> article = Article.last
=> #<Article id:1, ...>
>> {edit:3, view:10}.each do |trigger, count|
?>   count.times do
?>     Event.new(trigger: trigger).tap{ |e| e.article= article; e.save! }
?>   end
=> {:edit => 3, :view => 10}
>> Event.count
=> 13
>> Event.group(:trigger).count
=> {"edit" => 3, "view" => 10}

Tip 16: Allow you to Override Associations

car.rb
1
2
3
4
5
6
7
8
9
  class Car < ActiveRecord::Base
    belongs_to :owner
    belongs_to :previous_owner, class_name: "Owner"

    def owner=(new_owner)
      self.previous_owner = owner
      super
    end
  end

Tip 17: Instantiate Records without a database

$ rails c

>> User.find(1)
=> #<User id: 1, name: "James", ...>
>> jeg2 = User.instantiate("id" => 1, "email" => "james@example.com")
=> #<User id:1, email:"james@example.com">
>> jeg2.name = "James Edward Gray II"
>>jeg2.save!
=> true

伪造一条记录。

TODO ….

Ruby全局变量表

| Comments

Ruby全局变量表, 记录。


名字 English库名 中文释义 返回值
- - - -
$0 $PROGRAM_NAME 程序名字 字符串
$* $ARGV 参数值 数组
$: 库加载路径 数组
$? $CHILD_STATUS 系统退出时,最后一个子进程的状态 整数
$” $LOADED_FEATURES 已加载的特性 数组
$$ $PID或$PROCESS_ID 进程号 整数
$! $ERROR_INFO 错误信息 字符串
$@ $ERROR_POSITION 错误发生的位置 字符串
$< $DEFUALT_INPUT 默认输入值设备 对象实例
$> $DEFAULT_OUTPUT 默认输出设备 对象实例
$; $FS或$FILED_SEPARATOR 默认字段分隔符,String.split方法会用到 字符串
$, $OFS或$OUTPUT_FIELD_SEPARATOR或 输入字符串分隔符,连接多个字 符串时用到|字符串
$_ $LAST_READ_LINE Kernel.puts或Kernel.readline从输入设备中读取的最后一行 字符串
$. $NR或$INPUT_LINE_NUMBER 当前所读取文件的最后行号 整数
$/ $RS或INPUT_RECORD_SEPARATOR 输入分隔符,即输入结束符 字符串
$\ $OFS或$OUTPUT_RECORD_SEPARATOR 多个Kernel.print或IO.write调用时,各个输出记录的分隔符 字符串
$= $IGNORECASE 匹配时是否忽略大小写,已经作废 布尔
$& $MATCH 匹配结果 字符串
$1~$9 各组匹配结果 字符串
$~ $LAST_MATCH_INFO 最后一次匹配数据 MatchData实例
$+ $LAST_PAREN_MATCH 最后一个括号匹配内容 字符串
$` $PREMATCH 最后一次匹配前的内容 字符串
$’ $POSTMATCH 最后一次匹配后的内容 字符串

Ruby的并发世界

| Comments

这是我去年翻译的一篇旧文,放到thinkinweb.heroku.com上面, 现在搬过来。


注: 并发给我们的应用带来并行能力,而线程是实现并发的一种方式。Ruby的GIL限制了Ruby的多线程并发能力。

原文这里: 翻译过程中省略了一些废话。


       并发无疑不是一个新问题。但是随着多核时代的到来,web流量的剧增,一些新的技术出现,貌似更好,因为他们能更好的处理并性。

       并发就是多任务,可以这么理解。当人们谈论他们想要并发,意思就是他们想要代码在同一时间做多个不同的事情。当你用电脑的时候,你并不希望必须得在浏览网站和听音乐间二选一,你当然愿意二者可以并发进行了!一个道理,如果你有一个web服务,你当然不想一个进程每次只能处理一个请求吧。本文的目标是用尽可能简单的解释ruby的并发理论。 这是一个复杂的主题以及包含不同的并发实现方案。

       我们期望我们的代码有更好的性能,更快。让我们以2个简单具体的例子来说明并发。首先,我们假设你在写一个twitter客户端, 你可能想让用户当有新消息获取到的时候自动更新他/她的消息列表(tweets)。 要实现这个功能,一个通用的解决方案就是使用多个线程(Threads). 我们用一个线程去循环消息列表,另一个线程向远程Twitter API发起请求。2个线程共享同一片内容,所以一旦Twitter API线程获取了数据,就可以马上显示到页面上。

       第二个例子是webserver. 假设你的rails应用可能多于1QPS(每秒查询/请求数),你衡量你应用的平均应答时间大概是100ms。那么你的rails用一个独立的进程可以处理10QPS( 1秒1000ms , 100ms一个来回,那就是10QPS) 但是当你的应用每秒得到了大于10个请求数会如何呢? 其实也没啥,请求将会等待知道超时。 这就是为什么我们想提高我们的并发处理能力了。这里有很多不同的方法去实现它。

       很多人对这些不同的解决方案有不同的争议,但是他们从来没有说明过,为什么他们不喜欢其中一种方案,或者是觉得这种方案比那种好。 你可能经常听到人们讨论,类似于这样的话题: Rails can’t scale, 你只能使用 JRuby, threads suck 来得到并发, 唯一的并发处理是通过线程,我们应该选择 Erlang/Node.js/Scala, 使用 fibers可能更好,增加多台机器, 以及 forking > threading. 以上这些言论经常在twitter,blog上说的多了,所以你可能开始相信这些人的话了。但是你真的理解人们为什么那么说吗?你确信他们说的就是对的?

       真相就是,这是个很复杂的问题, 还好,它还不是太复杂。

       有件事你必须要记住,你所使用的语言已经定义好了并性模型。 在java里, threading is the usual solution, 如果你想在你的java应用里去实现并发处理,只需要在它自己的线程里运行独立的请求。在php里, 每个请求都会启动一个新的进程。 两者都有优缺点, 优点是,java线程方法共享内存,所以你可以节省内存。php的优点是,你不用去担心锁,死锁,线程安全编码和隐藏于线程背后的所有混乱。描述的如此简单,但是你可能会想,为什么php没有线程,而java就不能用多个进程? 这其实和语言的设计有关。php是为web而创的语言, php代码应该很快的被加载,不用太多的内存。java代码启动慢,还占用很大内存。java是一种通用的编程语言,而不是专门为web设计的。另一些编程语言比如Erlang和Scala都使用第三种方法: the actor model (角色模型)。 角色模型有点混合以上2种方案的模型,所不同的是,角色模型是一个不共享相同内存上下文的线程。actors直接的通信是通过交换信息,确保每个actor处理它自己的状态,从而避免损坏数据(2个线程同时修改同一数据,但是一个actor在同时接受2个信息)。 我们会在之后讨论这个设计模式,所以如果感到困惑,请不必担心。

       那么Ruby怎么样呢?Ruby开发者是不是使用线程,多进程,actors,其他? 答案是:Yes!

Threads 线程

       从1.9版开始,Ruby有了本地线程(之前是green threads)。 所以,如果我们愿意,我们完全可以像大多数的java开发者一样,随时随地的使用线程。但问题是,Ruby像Python那样使用了一个Global Interpreter Lock(aka GIL).这个GIL是一个保护数据完整性的锁机制。GIL每次只允许数据被一个线程修改,因此不让线程损坏数据,也不允许其真正的并发运行。这就是为什么有些人说,Ruby和Python并不具备真正的并发性。

       然而这些人们通常并没有提及, GIL使单线程程序更快, 多线程程序更易于开发,因为数据结构是安全的,还有许多c扩展是非线程安全,没有GIL这些c扩展就不那么循规蹈矩了。这些论据并没有说服大家,这就是为什么你会听到有些人说,你应该去看看另一些没有GIL的ruby实现,像什么JRuby, Rubinius(hydra分支)或者是MacRuby(Rubinius && MacRuby也提供另一种并发方式)。如果你用一个没有GIL的实现, 那么用ruby的线程实际和java的优缺点差不多了。但是,这也意味着,现在你又掉入了处理线程的噩梦中:需要确定你数据安全性, 不能死锁,检查代码,库文件,插件和gems是不是都是线程安全的。此外,运行过多的线程可能会影响性能,因为你的操作系统并没有足够的资源分配,它最终会将时间耗费在上下文的切换上。剩下的就由你自己来看是否值得在你的项目使用多线程了。

Multiple processes & forking 多进程&forking

       这是使用Ruby和Python使用并发最常用的解决方案。因为默认的语言并没有能力实现真正的并发,或者因为你想避免线程编程的挑战,你可能想去开启更多的进程。如果你并不想在进程间共享状态,这是很容易的。 如果你想这样做的话,就需要去用DRb, 一个像RabbitMQ那样的消息站,或者是一个像Memcached那样的共享数据存储系统,又或者是数据库。需要说明的是,你现在需要使用大量的内存。如果你想运行5个Rails进程,并且你的应用使用100Mb, 那么你需要500Mb, 这可是很大的内存。这实际是发生在当你使用类似于Mongrel这样的web服务器时候的事实。现在另一些服务器,像Passenger和Unicorn发现另一种方式, 他们依赖unix forking。 这种unix环境写时拷贝实现的forking的优势在于,创建一个新的主进程的copy,并且时共享相同的物理内存。 然而,每个进程也能修改它自己的内存,并不会影响其他进程。所以,Passenger一个进程能加载100Mb的Rails应用,然后fork这个进程5次, 总共只占用内存100多点Mb,并且你可以并行的去处理5倍的请求。这里注意,如果你在请求进程代码里分配内存,你的总内存将会增长,但是你仍然可以在内存用尽之前运行更多的进程。这种方式因其简单和安全而受人关注。 如果一个forked进程瞎捣蛋或者引起内存泄露,我们只需要删除它,然后创建个新的fork进程就ok了。 注意,这种方式也被应用于Resque, 一个异步job进程解决方案。

Actors/Fibers 角色/纤程

       之前我们谈到过Actor Model. 从Ruby1.9开始, 开发者又多了一个轻量级的线程,叫Fibers(纤程)。 Fibers不是一个角色(Actors), Ruby也没有实现本地角色模型(Actors Model),但是有些人基于fibers写了一些actor库。一个fiber像一个简单线程,只是它是基于语言级别的,并非虚拟机实现。Fibers就像一个block, 但是他们又可以暂停,可以回收。 Fibers比线程更快,且更省内存,看这个blog的示例。然而, 因为GIL, 你仍然不能在线程里真正的运行并发纤程。如果你想用多个cup核心,你可能需要运行多线程的运行纤程。所以, 纤程对并发有何帮助呢? 答案就是,他们是一个更大的解决方案的一部分。 Fiber允许开发者手工的控制调度“并发”代码,而且纤程本身也有代码在自动的调度其自身。这很棒,因为你现在可以用它自己的纤程包装一个web请求,告诉它返回一个response。同时, 你还可以继续处理下一个请求。每当一个fiber内部的请求被完成,它会自动的回收并且退出。听起来不错吧?那么,唯一的问题是, 如果你在一个纤程中,做任何类型的阻塞io操作,那么整个线程就会被阻塞,导致其他纤程也无法允许。诸如数据库/memcached查询, http请求,等等基本上你可能从控制器触发的任何东西,都会引起阻塞操作。好消息是,这个仅有的问题已经被解决, 就是要避免阻塞的IO。让我们看看这是如何做到的。

Non blocking IOs/Reactor pattern. 非阻塞IOs/Reactor 模式

       去理解reactor模式那真的是相当简单。阻塞IO的繁重工作委托给一个外部服务(reactor), 这个服务可以接受并发请求。 这个服务是一个回调处理器,根据响应的类型异步的触发事件。 让我做一个有限的比喻来说明这个更好的设计。 它有点像这样: 如果你问某人一个很难的问题, 他需要一段时间才能答复你,但是他的答复会让你决定举不举你的旗。你有两个选择,或者你选择等待,然后依据等到的结果举起旗,或者你的举旗逻辑已经被定义了,你只需要告诉他,什么样的答案是举旗,什么答案是不举旗,然后让他自己去做,然后你继续做你的事情, 而不必在那傻等了。第二种方式实际上就是reactor模式。它明显有点复杂, 但是关键的一点是, 它允许你的代码去定义基于响应去调用的methods/blocks。 这一点对于单线程webserver十分重要。 当一个请求来了,并且你的代码执行了数据库查询,你正在阻塞其他任何请求。为了避免这样, 我们可以包装我们的请求成为一个fiber, 触发一个异步的DB调用,暂停纤程,以便在我们等待db返回结果的过程中,另一个请求可以得到处理,一旦,db查询返回, 它就唤醒纤程, 然后给客户端返回响应。技术上讲,这个服务仍然是一次发送一个响应,但是现在是运行在了平行的纤程上,也不会被处理大量的阻塞操作阻塞主线程。

       这种方式被Twisted, EventMachine和Node.js所采用。Ruby开发者用EventMachine 或者是一个基于EventMachine的webserver,像Thin,和EM clients/drivers一样好的去处理异步非阻塞调用。得到Fiber的爱,你就能进入Ruby的并发世界。不过要小心的使用thin,非阻塞驱动和Rails的线程安全模式并不是意味着你可以处理并发请求。Thin/EM仅仅使用了一个线程,你需要让它知道,它可以正确处理下个请求。这是通过延迟响应来实现的,而且需要让reactor知道它。 这种方法最明确的问题是, 它会迫使你改变写代码的方式。你需要设置一堆callbacks,理解Fiber的语法, 并且要用延迟响应。 我不得不说,这是一种的痛!如果你看一些Node.js的代码,你会看到,它并不总是那么优雅。

Conclusion 总结

       综上所述, Ruby的高并发是可以实现的。但是真正的问题是什么?Ruby的GIL未来是什么? 我们应该移除它吗?其他的Ruby实现似乎相信如此,但是Rails仍然有一个mutex锁机制来限制一次只能处理一个请求。原因是因为有许多人都不写线程安全的代码,并且许多插件也不是线程安全的。

Ruby Styleguide

| Comments

注: 本文为Github Ruby Styleguide的中文翻译, 边翻译边过了一遍,发现这些风格约定很有其道理。推荐!

代码风格 (Coding Style)


  • 使用两个空格来保持缩进
  • 每行应该小于80个字符(Texmate和sublime text2 都可以设置
  • 末尾不要留空格
  • 在操作符前后, 逗号后面, 冒号和分号前后留空格。
1
2
3
4
5
    sum = 1 + 2
    a, b = 1, 2
    1 > 2 ? true : false; puts 'Hi'
    [1, 2, 3].each { |e| puts e }

  • 在(和[后面, 或者]和)前面不能有空格。
1
2
3
    some(arg).other
    [1, 2, 3].length

  • case和when应该保持同样的缩进深度.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    case
    when song.name == 'Misty'
      puts 'Not again!'
    when song.duration > 120
      puts 'Too long!'
    when Time.now.hour > 21
      puts "It's too late"
    else
      song.play
    end
    # another style
    kind = case year
           when 1850..1889 then 'Blues'
           when 1890..1909 then 'Ragtime'
           when 1910..1929 then 'New Orleans Jazz'
           when 1930..1939 then 'Swing'
           when 1940..1950 then 'Bebop'
           else 'Jazz'
           end

SublimeText2 使用指南

| Comments

引子:

昨天idecent向我推荐了一款编辑器 - Sublime Text 2。 经过试用,发现真的不错, 打开项目、文件的速度超快, 让Textmate汗颜, 于是毫不吝惜的把Textmate抛弃了。

注: SublimeText2是收费的,但不限制使用时间,只是不定时弹出让你付费的提醒。


使用指南:

为了方便在终端使用SublimeText2打开文件,需要加Link:

sudo ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl /usr/bin/st

使用技巧

一、启用vim模式

  • 打开配置文件: Preferences -> Settings User 或者使用快捷键:cmd + ,

  • 在配置文件中添加:

      "ignored_packages": []
    
  • 重启Sublime Text2就可以了。

二、 Package Control

Sublime Text 2拥有良好的扩展功能,这就是安装包(Package), 通过安装这个插件: Sublime Package Control

安装方法:

  • Control + ` 命令调出console.

  • 把下面的代码输入,并回车执行。

      import urllib2,os; pf='Package Control.sublime-package'; ipp=sublime.installed_packages_path(); os.makedirs(ipp) if not os.path.exists(ipp) else None; urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler())); open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read()); print 'Please restart Sublime Text to finish installation'
    
  • 重启Sublime Text2, 如果在 Preferences -> Package Settings中见到Package Control这一项,就说明安装成功了。

三、 通过Package Control 来安装其他插件

  • cmd + shift + p 调出命令框

  • 输入 install 调出 Package Control: Install Package 选项,按下回车。

  • 列表中查找你想安装的插件, 按下回车就会自动安装。 (某些插件是收费的)

  • 安装完记得重启Sublime Text 2.

推荐插件: 右键菜单增强: SideBarEnhancements

四、 无干扰模式(Distraction Free Mode)

在 Sublime Text 2 中,只要按下 Control + Shift + Command + F 或是在菜单 View 中选择 Enter Distraction Free Mode 就可以进入这个 UI 最小化模式了。如果是在用 Mac OS X Lion 的话,Sublime Text 2 还同时支持 Lion 的原生全屏模式。

通过修改 “Preferences” -> “File Settings - More” -> “Distraction Free - User” 可以对防干扰模式进行一些设置:

{
"line_numbers": false,      //是否显示行号
"gutter": false,            //是否显示边列
"draw_centered": true,      //是否居中显示
"wrap_width": 80,           //换行宽度(单位:字符)
"word_wrap": true,          //是否自动换行
"scroll_past_end": true     //滚动能否超过结尾
}

五、 Textmate Bundle

Sublime Text 2 很给力的一点就是它同时支持一些 TextMate 的 Bundle。

Sublime Text 2 对于 TextMate Bundle 中的 Snippet 有着良好的原生支持,把 Bundle 放到 Packages 目录里就能用。但对 Bundle 中的 command 并不支持.

我自己没有在Sublime Text2中使用textmate的bundle。

六、 安装主题

可以使用Package Control来查找Theme,选择主题安装, 但是安装完之后,需要看你下载的theme插件的Readme来进行配置。

七、 快捷键

Navigation

* Command palette: Command + Shift + P   
*  Fuzzy finder: Command + P
*  Function crawling: Command + R
*  Go to line number: Control + G
*  Find in files: Command + Shift + F

Text manipulation

* Replace in file: Command + Alt + F (Control + H on Windows)
* Select current line: Command + L
* Duplicate line: Command + Shift + D
* Multi-select words: Command + D, multiple times
* Swipe lines: Command + Shift + L, or Control + Shift + Up/Down
* Join lines: Command + J
* Delete to beginning of word: Control + Backspace
* Delete to end of word: Control + Delete

Coding

* Edit occurrences : Command + Control + G (Alt + F3 on Windows)
* Auto-align assignments: Command + Shift + A
* Select scope: Command + Shift + Space, multiple times
* Jump to matching bracket: Control + M
* Toggle comment: Command + /

Rails Edge - 使用Rails来做API-Only App

| Comments

原文地址: 点这里 或者 这里Edge Guides

本文并非原文翻译


这个导读你会学到:

  • 什么是仅提供API的Rails应用

  • 开始如何配置没有任何浏览器特性的Rails

  • 如何选择你想包含的middlewares

  • 如何选择你的controller里使用哪个modules

注意: 这个导读引入的特性并没有被全部实现。 先当文档来看

什么是一个API app?

传统意义上来说, 当人们说他用了Rails实现了一个“API”, 意味着他们的web应用提供一个程序可访问的API接口。就像Github提供的这个API, 你可以在你自己定制的客户端来使用它。

随着移动互联网时代的到来,以及各种客户端框架的出现, 越来越多的开发者使用Rails来构建后端, 供Web应用和本地应用(Native App)一起使用。例如, Twitter就在Web Application中和其他本地应用客户端(Native App)一样,都消耗着由自己的公共API提供的JSON资源, 而不是通过Rails生成动态的HTML来渲染用于和Server端通信的表单和链接。大多少开发者都把Web应用当作由HTML, CSS, Javascript构成的另一种客户端来处理,只是通过JSON来通信。

Solr简要指南

| Comments

一、 安装

服务器环境, CentOS, 需要的软件有: jdk 1.6.0 、apache-solr-3.1.0 、apache-tomcat-7.0.26 、 mmseg4j

Solr与Sphinx相比较的优势:

  • Solr 可以精确控制对索引进行局部更新,而Sphinx只能全局更新.

  • Solr 可以对几乎任何对象进行索引,该对象甚至可以不是ActiveRecord.而Sphinx和RDBMS耦合过于紧密.

  • Solr 索引的对象ID可以非空或者是字符串,而Sphinx要求被索引对象必须拥有非0整数作为ID.

  • Solr 支持Boolean作为查询条件搜索,更加方便

  • Solr 支持Facets,而Sphinx为此需要做更多工作

  • Solr 是对lucene的包装。所以他可以享受lucene每次升级带来的便利。

Bcrypt与密码安全

| Comments

最近闹的沸沸扬扬的各大网站用户密码泄露事件, 让网民们震惊了,尽然都是明文保存密码。因为存在某些漏洞,比如sql注入, 可能让Hacker拿到全字段的数据列表,如果是明文密码, 那就帮Hacker省事了, Hacker都不需要暴力破解了。

其实对于密码有很多加密手段,但是最安全的莫过于Bcrypt这种算法了, 详细的参看Coda Hala的这篇文章, 也有中文版。 其实安全也是相对的, 对于Bcrypt这种算法的优势再于它的慢, 延缓了Hacker暴力破解的时间, 对于用户来说,就相对安全了。

用Rails的同学就有福了。 devise默认就是支持Bcrypt的。

initializers/devise.rb
1
  config.stretches = Rails.env.test? ? 1 : 10

这里的stretches被用来做work factor, 数值越大越慢, 如果你发现一个crypt生成值在20毫秒之内,那这个stretches就正好。

另一个措施就是可以在用户输入12345之类的弱密码的时候,禁止其注册,并提示其使用强度比较高的密码。

内心

| Comments

在微博上看到@周伯通招聘发的这个帖子设立职业生涯目标的14步练习法, 就看了看, 并且按照这个步骤完成了自己的练习。结果发现自己内心的那个想法竟然如此墙裂 。。。

步骤1. (省略,参考上面帖子地址)

我想拥有的:

一个公司, 不算很大, 最好不要超过20个人。 公司以技术为重, 公司的产品导向是通过科技手段改善人类的生活,做最实用又最有创意的产品。 基于互联网,又高于互联网, 贴近生活与大众, 或者某个垂直行业, 充满了想象力, 去发现生活中美与不同的一面, 带给用户简单,美与便利。

公司里没有HR, 或者说没有那些只会记录员工工作时间的HR, 我觉得真正的HR更像一个保姆,公司的保姆, 除了那些日常的事务, 还应该做的是,维持公司内部员工的工作环境,工作心情, 解决公司员工碰到的各种困难。 公司的企业文化是大家一起来创造的,工作时间随意, 前提是保质保量完成工作任务。 我觉得,只有公司把员工当成家人, 员工才有可能把公司当做家。 公司每周都组织家庭聚会, 一起去郊外旅游, 聚餐, 交流思想。 公司不以上市做为目标, 所以公司不会拿所谓的期权来忽悠人, 每个月的财务会公开, 年底人人都会有分红。分红不是按等级分配,也不是按劳分配, 是按功劳分配, 对公司产品有贡献的人, 才能拿到高比例的分红。 如何去衡量对产品有贡献,可以通过多种手段, 比如,一个漂亮的对策解决了用户反馈的产品问题, 一个漂亮的营销策划方案, 一个漂亮的产品功能改进, 一个漂亮的家庭聚会活动组织,一个漂亮的技术分享或者是贡献等等, 当然漂亮不漂亮,公司的每位同事都会参与打分, 这也是公司人少的好处。

同事间的协作方式,可以是远程协作。 比如,今天不舒服, 可以在家办公,或者是去咖啡馆, 只要是任何有网络的地方。像北京这类地方, 交通拥堵, 在北京郊区或者周边买房租房的优秀人才也不少。 没必要每天都往一个办公室挤。 每周保持2 的天正常会面就ok了。 这样的话, 同事们就不必要每天为了想在北京买房而发愁了, 你在北京周边买也一样, 公司支持你(精神上,公司文化,金钱上估计前三五年还没那个实力)。

我觉得公司也应该有理想, 公司的理想应该反映在其产品上,就向苹果的产品一样, 果粉所热爱的苹果,绝对不是其可以用来装逼的价格, 真正的果粉懂得,因为其提升了人们的审美, 告诉大众什么是美,带给人们好心情; 带给了人们方便, 手势, 快捷键等提升了工作效率。所以,公司的理想通过产品反映给大众, 能提升大众生活精神质量的公司理想, 大众肯定可以接受, 产品自然就会有市场。

  1. 在你生活中,你认为哪五件事情最有价值?

    • 做有意义的工作
    • 和家人共处的时光, 能多抽时间陪父母, 抽空去看望老朋友, 多交流。
    • 信仰(基督教)
    • 健康。 每周适度的锻炼。(不包括挤公车地铁)
    • 学习。 必不可少。
  2. 在你的生活中,有哪三个最重要的目标?

    • 创业。 去建立一个我上面所描写的公司。
    • 经营一个和谐幸福的家庭。
    • 保持一个健康的身体。
  3. 假如你只有六个月的生命,你会如何地运用这六个月?

    • 去旅行。 带着我的爱人, 父母, 岳父岳母和我弟弟。给我的亲戚和其他朋友们邮寄明信片。
  4. 假如你立刻成为百万富翁,在哪些事情上,你的做法会和今天不一样?

    • 可能对创业的想法更坚定了, 也许会马上踏出那一步.
  5. 有哪些事是你一直想做,但却不敢尝试去做的?

    • 去创上面描述的公司(虽然以前也创过业)
  6. 在生活中,有哪些活动,你觉得最重要的?

    • 交流(或者头脑风暴), 聚餐, 一起去郊游,健身, 做礼拜。
  7. 假如你确定自己不会失败(拥有充实的时间、资源、能力等),你会敢于梦想哪一件事情?

    • 第一 , 当然是去创建上面描述的那个公司。
    • 第二, 去旅行。 带着我的爱人, 父母, 岳父岳母和我弟弟。给我的亲戚和其他朋友们邮寄明信片。

步骤2.

  • 以上所写,我希望可以在10年之内达成。2012 - 2022。

步骤3.

2012年主要目标:

  1. 在AR方向上,能做一些东西出来。 (时限一年, 年底正式发布, 之前会出测试)
  2. 抽出来时间,去看老朋友。
  3. 和老婆的蜜月旅行。(国庆长假+年假)
  4. 坚持锻炼,减肥。
  5. 每个月坚持看一本书。

步骤4.

  1. 用肯定的语气来预期你的结果,说出你希望的而非不希望的; √
  2. 结果要尽可能具体,还要明确订出完成的期限与项目; √
  3. 事情完成时你要能知道完成了; √
  4. 要能抓住主动权,而非任人左右;√
  5. 是否对社会有利。 √

步骤5.

  • 比较执着, 不撞南墙不回头。脾气急躁, 但是在改。 碰到问题的时候, 缺乏冷静。 合作伙伴已有,财力支持也比较确定。 时限有一些吃紧, 能力,应该达标了。

步骤6.

  1. 专业能力
  2. 同一个志向,或者愿望
  3. 经常性的交流
  4. 利益驱动
  5. 对用户来说, 我做出了正宗并实惠的东西, 不存在欺骗用户的行为。
  6. 业界大佬来帮忙。 是我用真诚换来的。虽然之后的发展让人失望。

步骤7.

  • 团队, 起步的财力, 共同的目标, 坚持。

步骤8.

  • 没有足够的财力支持。 补救办法, 参考 《Rework》。

步骤9.

  1. 在AR方向上,能做一些东西出来。 (时限一年, 年底正式发布, 之前会出测试)

    • 正式发布
    • 测试数据采集, 修正bug
    • 发布beta版
    • 构建产品, 先出测试版
    • 产品功能确定
    • UE设计
    • 技术考察
    • 人员集结, 投资到位
  2. 抽出来时间,去看老朋友。

    • 每一个月找个周末。
  3. 和老婆的蜜月旅行。

    • 国庆长假+年假, 2012来年就需要办理签证事宜。
  4. 坚持锻炼,减肥。

    • 春夏秋,小区会所游泳
    • 冬, 小区周围跑步
  5. 每个月坚持看一本书

步骤10.

步骤11.使目标多样化且有整体意义。

  • 已经很多样化了。

步骤12.为自己创造一个适当的环境。

步骤13.经常反省所做的结果。

步骤14.

  • 仔细想了想以后, 要感谢的人有好多。 要学会感恩。在感恩中前进。

总结:

经过这样的练习, 发现自己内心的那个想法竟然那么墙裂。

关键的2012, 把握内心所想, 脚踏实地向着目标踏步走!!!