Ruby On Rails 常用的精品Gem汇总

首先需要注明一点,本文是原创的并不是从其它地方转载。所有的数据是我从 GitHub 和 RubyGems 上码下来的,数据的截取时间就是本文的发布日期。

RubyGems 的下载量可以看到在用这个 gem 的人数,所以数值很大(这里收藏的下载量至少会大于10万级)。而在 GitHub 上的则代表关注这个gem的源码的人数(本文收藏的至少是过 1k以上 Star 的 repository)

Nokogiri

gem 'nokogiri'

采集数据是我们需要解析复杂的 HTML 结构,从中获得需要的数据,Nokogiri 可以帮助我们完美的处理不同网页上面不同的 HTML 结构,并且有很好的编码处理能力,用它你不用担心页面是 GB2312 还是 GBK 还是 UTF-8,它都很很好的处理,解析结构可以用类似 jQuery 的 CSS Selector 的方式查找,很是方便。曾经用过 Ruby 的好几个类似插件,最终发现 Nokogiri 才是最好的。

Faraday

gem 'faraday', '~> 0.9.1'

Faraday 是一个HTTP的客户端,可以提供一般化的接口和多种的适配器 (例如 Net::HTTP)。

做一些网络服务API集成它是一个很好用的助手。

conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
  faraday.request  :url_encoded             # form-encode POST params
  faraday.response :logger                  # log requests to STDOUT
  faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
end

## GET ##
response = conn.get '/nigiri/sake.json'     # GET http://sushi.com/nigiri/sake.json
response.body

conn.get '/nigiri', { :name => 'Maguro' }   # GET http://sushi.com/nigiri?name=Maguro

conn.get do |req|                           # GET http://sushi.com/search?page=2&limit=100
  req.url '/search', :page => 2
  req.params['limit'] = 100
end

## POST ##
conn.post '/nigiri', { :name => 'Maguro' }  # POST "name=maguro" to http://sushi.com/nigiri

# post payload as JSON instead of "www-form-urlencoded" encoding:
conn.post do |req|
  req.url '/nigiri'
  req.headers['Content-Type'] = 'application/json'
  req.body = '{ "name": "Unagi" }'
end

## Per-request options ##

conn.get do |req|
  req.url '/search'
  req.options.timeout = 5           # open/read timeout in seconds
  req.options.open_timeout = 2      # connection open timeout in seconds
end

RSPEC-RAILS

gem 'rspec-rails', '~> 3.4'

如果没有用过 RSpec 都不能算是懂 Ruby 吧,respec_rails 顾名思义是将 rspec 集成至 rails 中的测试框架了:

require "spec_helper"

describe User do
  it "orders by last name" do
    lindeman = User.create!(first_name: "Andy", last_name: "Lindeman")
    chelimsky = User.create!(first_name: "David", last_name: "Chelimsky")

    expect(User.ordered_by_last_name).to eq([chelimsky, lindeman])
  end
end

Devise

gem 'devise', '~> 3.5', '>= 3.5.2'

Devise 是一个用于快速构建基本用户功能,如:注册,登陆,找回密码。 同时它还集成了第三方的登入支持,代码也相当简单:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 20
end

Devise 是一个大集成包,单看看它集成了什么就能知道到大至上的功能了:

  • Database Authenticatable: 支持加密的身份验证并能将验证信息存储于数据内。
  • Omniauthable: 集成 OmniAuth 实现三方平台(如: Twitter, Facebook, 新浪微博, 腾讯 QQ)账号登陆的支持。
  • Confirmable: 发送邮件以验证注册用户的身份。
  • Recoverable: 支持密码重置。
  • Registerable:支持注册新用户。
  • Rememberable: 支持自动登录
  • Trackable: 可跟踪用户的登入次数,时间戳和 IP
  • Timeoutable: 支持自动用户会话的过期
  • Validatable: 可验证用户的邮件的与密码的正确性,且可定制化。
  • Lockable: 可以锁定多次尝试登录失败的用户账号。

如果没有它,光想想要我们自己来码上面的这些功能都够浪费时间的。重点是每个项目都得用啊。

FACTORY_GIRL_RAILS

gem 'factory_girl_rails'

Factory Girl可能是ROR测试中最常用到的数据工厂,没有它也只能手工写Fixture了。不解释了,它太常用了。

# spec/factories/user.rb
FactoryGirl.define do
  factory :user do
    first_name "Andy"
    last_name  "Lindeman"
  end
end

# spec/models/user_spec.rb
require "spec_helper"

describe User do
  it "orders by last name" do
    lindeman = create(:user)
    chelimsky = create(:user, first_name: "David", last_name: "Chelimsky")

    expect(User.ordered_by_last_name).to eq([chelimsky, lindeman])
  end
end

Better Errors

gem "better_errors"

它用一个更好的,更有用的错误页替换标准的 Rails 错误页面,对 Rack middleware 也同样有效。

4百多万的下载,可见美观是很能吸引我们这些外观第一的程序员的。

twitter-bootstrap-rails

gem "therubyracer"
gem "less-rails" 
gem "twitter-bootstrap-rails"

来自 Twitter 的 Bootstrap,是一套完成的前台 CSS 框架。以简洁,优雅著称于世。被无数攻城狮所青睐,又让无数程序猿审美疲劳。不用不行啊~

分页控件

will_paginate

gem 'will_paginate', '~> 3.0.6'

Kaminari

gem 'kaminari'

Kaminari 支持多种的 ORM (ActiveRecord, Mongoid) 和多种的Web框架 (Rails, Sinatra, Grape), 以及多种的模板引擎 (ERB, Haml, Slim).

从数字上两者都只在伯仲之间,只是will_paginate 比较老, 应用案例较多, kaminari 更新, 性能和兼容性更好。

计划任务

有时候一些任务的执行会很慢,而这些任务我们并不要求需要马上返回结果 (比如:发送邮件,生成图片缩略图),那我们可以选择将这些任务放到后台执行,以便于页面不会长时间等待执行,我们还是将其统称为计划任务吧。

在这方面的有不少出色的 gem, 其粉丝也不在少数

Resque

gem 'resque', '~> 1.25', '>= 1.25.2'

Resque 是一个基于 Redis 的后台任务处理gem。后台工作可以是任何一个Ruby类或者模块。

Resque 相比于 DelayedJob 会是一个更加重型的gem。与 DelayedJob 的不同之处主要有三:

  • 它是一个用于创建、查询、处理 的 Ruby 库
  • 它是一个起动后台处理Worker的Rake任务。
  • 它是一个Sinatra app 用于检测队列、工作和Workers.
class Archive
  @queue = :file_serve

  def self.perform(repo_id, branch = 'master')
    repo = Repository.find(repo_id)
    repo.create_archive(branch)
  end
end
class Repository
  def async_create_archive(branch)
    Resque.enqueue(Archive, self.id, branch)
  end
end

Sidekiq

gem 'sidekiq'

号称性能要比 Reque 和 delayed_job 都要高,具体的数据你可以上它们的 GitHub 上看,有一个完整的对比表。但明显在程序员的受欢迎度上还是要差于 Resque。

Resque 和 Sidekiq 都使用的 redis 作为任务数据存储,这块是差不多的,主要的区别还是在多任务处理的方式是不一样的。

resque 使用的是一个 worker 通过 fork 方式来产生多个 worker 处理多个任务,而 sidekiq 是一个 worker 使用的 Thread 方式产生多个线程 处理多个任务。

那 fork 方式和 thread 方式有什么区别呢?

fork 方式

fork 一个进程,操作系统会建立一个独立分开的地址空间,并且从父进程复制所有的内存片段到这个地址里面去。 这就意味着对于操作系统来说,对于 fork 的进程切换上下文,因为需要保存和加载所有数据,所以代价更大。 而且如果父进程死掉了,这些 fork 的子进程没有退出的话,将会变成僵尸进程。

thread 方式

多线程的话是共享地址空间,内存并且多线程之间的交互也比较方便。而且你也不用担心僵尸进程的问题,一旦进程死掉, 所有的线程会自动被杀掉。但这种方式也有缺点,你必须保证代码是线程安全的,不然可能会引起麻烦。

不难得出

  • resque 比 sidekiq 更消耗内存
  • resque 的 worker 代码没有必要担心线程安全问题,但 sidekiq 必须考虑

DELAYED_JOB

gem 'delayed_job_active_record'

DelayedJob 是一个轻量型的gem,使用起来也相当的简单,而且它可以配合一个 progress bars 控件检测任务的执行进度(可能这也是它除了轻量以外的最大特点)。

# without delayed_job
Notifier.signup(@user).deliver

# with delayed_job
Notifier.delay.signup(@user)

# with delayed_job running at a specific time
Notifier.delay(run_at: 5.minutes.from_now).signup(@user)

Whenever

gem 'whenever', :require => false

Linux 里面有 Cron 可以帮助我们定期执行一些任务,但是 Cron 手动写起来很是麻烦,尤其是前面时间周期的定义, Whenever 可以帮助我们用更人性化的方式编写 Cron 任务,看看出他的示例代码:

every 3.hours do
  runner "MyModel.some_process"
  rake "my:rake:task"
  command "/usr/bin/my_great_command"
end

every 1.day, :at => '4:30 am' do
  runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end

every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
  runner "SomeModel.ladeeda"
end

every :sunday, :at => '12pm' do # Use any day of the week or :weekend, :weekday
  runner "Task.do_something_great"
end

every '0 0 27-31 * *' do
  command "echo 'you can use raw cron syntax too'"
end

# run this task only on servers with the :app role in Capistrano
# see Capistrano roles section below
every :day, :at => '12:20am', :roles => [:app] do
  rake "app_server:task"
end

它的 DSL 很简单,直接,暴力易懂!

我个人是推荐使用 Resque 的。

上传组件

Paperclip

gem "paperclip", "~> 4.3"

Paperclip 是老牌产品了,也是几乎绝大多数项目都有在用它,它可以帮你处理上传图片,裁减,定义不同的图片尺寸,几乎很完美。(with the support of ImageMagick)

# Rail4
class User < ActiveRecord::Base
  has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
  validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
end

Carrierwave

gem 'carrierwave'

Carrierwave 是后起之秀,功能和 Paperclip 差不多,但它还可以管理除图片之外的东西,而且灵活性更高。

对比

Paperclip 官方只支持 ActiveRecord 但相对稳定, 而 Carrierwave 比较灵活支持更多的 ORM, 比如 mongoid

If you feel adventurous, you can try refile from the creators of carrierwave.

表单

Rails 为我们带来和一改传统的表单构件方式,但是经过实际的使用,我们渐渐发觉这样依然还是不够“敏捷”,我们需要更加简便并具有更细致规范的表单,所以有了 Formtastic ,它用起来比 Rails 默认的 form 更加简洁,但是却具有更多的功能,你可以为每个字段设定 help-text 放到文本框下面,并可以走 I18n 的方式设置语言。simple_form 和 Formtastic 功能类似,但它的写法还要简单一些。

SIMPLE_FORM

gem 'simple_form'

SimpleForm 在用法上与 Formtastic 类似,同样很好的支持了I18n、表间关联、嵌套表单和表单验证等常用的功能。SimpleForm 从 2.0 开始,在可定制性上有质的突破(Twitter Bootstrap 在里边起了很关键的作用),现在的它更像是一个 Form Builder 框架,可以很方便的对它进行设置和扩展。

看看 simple_form 的用法 :

= simple_form_for @user do |f|
  = f.input :username, label: 'Your username please'
  = f.input :password, hint: 'No special characters.'
  = f.input :email, placeholder: 'user@domain.com'
  = f.input :remember_me, inline_label: 'Yes, remember me'
  = f.button :submit

Formtastic

gem 'formtastic', '~> 3.0'

Formtastic 的主要缺点在于对HTML输出的可定制性上不够灵活。目前的系统中,想要满足各种表单的需求,就需要在每个表单页写很多重复的代码进行设置,甚至很多页面都在使用 Rails 原生的 Form Builder,这样做维护量太大。

  <%= semantic_form_for @post do |f| %>
    <%= f.inputs do %>
      <%= f.input :title %>
      <%= f.input :body %>
      <%= f.input :section, :as => :radio %>
      <%= f.input :categories %>
      <%= f.input :created_at, :as => :string %>
    <% end %>
    <%= f.actions do %>
      <%= f.action :submit, :as => :button %>
      <%= f.action :cancel, :as => :link %>
    <% end %>
  <% end %>

Grape

gem 'grape'

随着 Mobile App 的增多,很多时候我们在做用 Rails 做 API Base 项目时,rails 自带的 C 和 V 层显得过于繁杂,grape 可以帮助我们快速的构建和 Rails 完美融合的 API 接口。

module Twitter
  class API < Grape::API
    version 'v1', using: :header, vendor: 'twitter'
    format :json
    prefix :api

    helpers do
      def current_user
        @current_user ||= User.authorize!(env)
      end

      def authenticate!
        error!('401 Unauthorized', 401) unless current_user
      end
    end

    resource :statuses do
      desc 'Return a public timeline.'
      get :public_timeline do
        Status.limit(20)
      end

      desc 'Return a personal timeline.'
      get :home_timeline do
        authenticate!
        current_user.statuses.limit(20)
      end

      desc 'Return a status.'
      params do
        requires :id, type: Integer, desc: 'Status id.'
      end
      route_param :id do
        get do
          Status.find(params[:id])
        end
      end

      desc 'Create a status.'
      params do
        requires :status, type: String, desc: 'Your status.'
      end
      post do
        authenticate!
        Status.create!({
          user: current_user,
          text: params[:status]
        })
      end

      desc 'Update a status.'
      params do
        requires :id, type: String, desc: 'Status ID.'
        requires :status, type: String, desc: 'Your status.'
      end
      put ':id' do
        authenticate!
        current_user.statuses.find(params[:id]).update({
          user: current_user,
          text: params[:status]
        })
      end

      desc 'Delete a status.'
      params do
        requires :id, type: String, desc: 'Status ID.'
      end
      delete ':id' do
        authenticate!
        current_user.statuses.find(params[:id]).destroy
      end
    end
  end
end

CANCANCAN

gem 'cancancan', '~> 1.10'

它是 CanCan 项目的代替品,它其实就是为我们的应用加入操作权限控制,而且比较好的地方是可以将所有的操作权限放在至到一个独立的文件之中。

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.admin?
      can :manage, :all
    else
      can :read, :all
    end
  end
end

而它的另一个比较新后来者就可以数 pundit 了, 由于在RubyGems上的下载量才7万多,所以就不独列出数了。但值得注意的是它在GitHub上的start是6K多,已超越CanCanCan的Repository。

如果有做过操作权限控制的朋友可能都会发现,操作极权限控制是很耗费性能的,而 pundit 则号称在性能上会超越 CanCanCan,

Pundit 更为模块化,对于体量较大的程序我觉得更为之合适,至少不会写出一个几百行的大文件出来,不利于维护。

ActiveAdmin

gem 'activeadmin', github: 'activeadmin'

这是一个相当不错的管理界面应用gem, 基本不需要做什么需求就能上项目了。从RubyGems的百万级下载量也可以得知其受欢迎的程度了。感觉上是有点仿 Wordpress 的 Dashboard。

我个人是很喜欢 ActivateAdmin 的DSL定义的,因为既简单又快速:

ActiveAdmin.register Product do
    scope :all, default: true
    scope :available
    scope :drafts

    filter :title
    filter :author, as: :select, collection: ->{ Product.authors }
    filter :price
    filter :create_at

    index do
        column :title
        column "Price", sortable: :price do |product|
            number_to_currency product.price
        end
        defualt_actions
    end
end 

这样的代码几乎就是秒懂,不解释了。这家伙谁用谁说好 _

他们的官网也做得挺好的,这里是一些关于 ActivateAdmin 的资源链接:

相关 gem

rails_admin

$ rails g rails_admin:install

与 ActiveAdmin 相比 rails_admin 就逊色的多了,但在 GitHub 上却表现不俗。在代码质量上其实两者相去不远,只是 ActiveAdmin 更好看一些,而 rails_admin 的界面就做得有点渣,要上项目的话必须得作出很多的修改。

以下是 rails_admin 的特色:

  • 对任何数据都可支持 CRUD
  • 自定义操作
  • 自动化表单验证
  • 支持查找与过滤
  • 可以将数据导出为 CSV/JSON/XML 格式
  • 支持 Devise 的身份验证
  • 支持 CanCanCan 或 Pundit 的权限判定
  • 通过 PaperTrail 支持用户操作历史
  • 支持多种ORM
    • ActiveRecord
    • Mongoid

Sunspot

gem 'sunspot_rails'
gem 'sunspot_solr' # optional pre-packaged Solr distribution for use in development

Sunspot 是一个 Solr 搜索引擎的 Ruby 库。它基于 RSolr 库构建,提供低级别的 Solr 集成接口。它的定义很简单,使用也相当容易,用DSL就可索引对象和启用搜索了。

它的主要特点:

  • 全文搜索
  • ActiveRecord
  • 英文分词

ActivateRecord 定义 可搜索对象

class Post < ActiveRecord::Base
  searchable do
    text :title, :body
    text :comments do
      comments.map { |comment| comment.body }
    end

    boolean :featured
    integer :blog_id
    integer :author_id
    integer :category_ids, :multiple => true
    double  :average_rating
    time    :published_at
    time    :expired_at

    string  :sort_title do
      title.downcase.gsub(/^(an?|the)/, '')
    end
  end
end

搜索

Post.search do
  fulltext 'best pizza'

  with :blog_id, 1
  with(:published_at).less_than Time.now
  order_by :published_at, :desc
  paginate :page => 2, :per_page => 15
  facet :category_ids, :author_id
end

小结

我这里没有列出 Rails 生成的那些常用 gem ,以上的都是一些我收集和常用的 gem 希望能对大家有用。

另外,如果您收藏了更好的 gem 希望能在本文留评,而且请注明 gem 的作用和 RubyGems 上的下载链接,给更多的Ruby的爱好者一个综合性的资源汇总,Thanks!

posted @ 2015-12-01 15:25  Ray Liang  阅读(4793)  评论(1编辑  收藏  举报