强大的Rails查询、搜索插件:SearchLogic

参考:http://github.com/binarylogic/searchlogic 

比较早就在用这个插件了,本来今天想响应蜗牛同学的号召,把这篇http://asciicasts.com/episodes/176-searchlogic给译一下,结果才译到第2句,发现译不下去。。还是乖乖写笔记吧。
 

Searchlogic是一个功能十分强大使用又很简单的Rails搜索插件。( BinaryLogic出品的两个插件真的很不错: AuthlogicSearchlogic) 

安装: 
Shell代码   收藏代码
  1. script/plugin install git://github.com/binarylogic/searchlogic.git  


扩展 
装上之后,所有的model都被添加上了一系列的类方法(其实是通过method_missing实现的,见源码: http://github.com/binarylogic/searchlogic/blob/master/lib/searchlogic/named_scopes/conditions.rb) 

这一系列的方法很容易看懂,直接copy官方的代码吧: 
Ruby代码   收藏代码
  1. #假设我们有如下的model  
  2. User(id: integer, created_at: datetime, username: string, age: integer)  
  3.   
  4. # Searchlogic会免费赠送给你这么一堆named scopes  
  5. User.username_equals("bjohnson")  
  6. User.username_equals(["bjohnson""thunt"])  
  7. User.username_equals("a".."b")  
  8. User.username_does_not_equal("bjohnson")  
  9. User.username_begins_with("bjohnson")  
  10. User.username_not_begin_with("bjohnson")  
  11. User.username_like("bjohnson")  
  12. User.username_not_like("bjohnson")  
  13. User.username_ends_with("bjohnson")  
  14. User.username_not_end_with("bjohnson")  
  15. User.age_greater_than(20)  
  16. User.age_greater_than_or_equal_to(20)  
  17. User.age_less_than(20)  
  18. User.age_less_than_or_equal_to(20)  
  19. User.username_null  
  20. User.username_not_null  
  21. User.username_blank  

这些方法的返回值都是一个named scope对象,因此你可以把它们串起来使用: 
Ruby代码   收藏代码
  1. scope = User.username_like("bjohnson").age_greater_than(20).id_less_than(55)  
  2. scope.all  
  3. scope.first  
  4. scope.count  
  5. # 等等...等啥?在rails console里试试看看效果哇  

完整的条件(conditions)列表见Searchlogic::NamedScopes::Conditions中的常量。 

别名 
作者说了,输入长长的“greater_than_or_equal_to”一点也不好玩,所以作者又为searchlogic添加了一系列别名: 
Ruby代码   收藏代码
  1. User.username_is(10)  # equals  
  2. User.username_eq(10)  # equals  
  3. User.id_lt(10)        # less than  
  4. User.id_lte(10)       # less than or equal to  
  5. User.id_gt(10)        # greater than  
  6. User.id_gte(10)       # greater than or equal to  
  7. # 等等...  


这些还不是searchlogic强大的地方。 

searchlogic还可以 搜索关联的对象(关联的数据库表),很简单: 
Ruby代码   收藏代码
  1. # 假设我们有以下的关联  
  2. User.has_many :orders  
  3. Order.has_many :line_items  
  4. LineItem  
  5.   
  6. # 设置关联对象的字段的搜索条件  
  7. User.orders_total_greater_than(20)  
  8. User.orders_line_items_price_greater_than(20)  
  9.   
  10. # 按照关联对象的某个字段排序  
  11. User.ascend_by_order_total  
  12. User.descend_by_orders_line_items_price  

wow 你一定已经惊呼了,不过还早。  

自定义的named scope 
因为这些方法的返回值都是named_scope,所以还可以这样用: 
Ruby代码   收藏代码
  1. LineItem.named_scope :expensive:conditions => "line_items.price > 500"  
  2.   
  3. User.orders_line_items_expensive  


多态关联 
更强大的来了: 
searchlogic为多态关联也提供了很好的支持: 
Java代码   收藏代码
  1. #假设有这样的关联:  
  2.   Audit.belongs_to :auditable, :polymorphic => true  
  3.   User.has_many :audits, :as => :auditable  
  4. #可以这样搜索  
  5.   Audit.auditable_user_type_username_equals("ben")  

方法的格式有点特别,包含了这样的格式的前缀: 
[多态关联的名字]_[关联的类型]_type 
不过还是比较好懂的,只要给关联起个好名字,读起来还是很DSL的  

强吧?还早还早  

all 和any 
Ruby代码   收藏代码
  1. User.username_like_any("bjohnson""thunt")   # 会发起一个查询,查找users表中username包含字符串bjohnson或者thunt的记录  
  2. User.username_like_all("bjohnson""thunt")   # 会发起一个查询,查找users表中username同时包含字符串bjohnson和thunt的记录  
  3. User.username_like_any(["bjohnson""thunt"]) # 也可以接受一个数组形式的参数  


or的使用 
Ruby代码   收藏代码
  1. User.username_or_first_name_like("ben")  
  2. => "username LIKE '%ben%' OR first_name like'%ben%'"  
  3.   
  4. User.id_or_age_lt_or_username_or_first_name_begins_with(10)  
  5. => "id < 10 OR age < 10 OR username LIKE 'ben%' OR first_name like'ben%'"  

注意,你并不需要每次都清楚的加上条件(例如gt、lt、begins_with等)。你只需要在结尾的部分指定。如果你在一个字段名后面加上另一个字段名,那么对这两个字段都将使用后面的条件。所以: 
Ruby代码   收藏代码
  1. User.username_like_or_first_name_like("ben")  

可以写成这样: 
Ruby代码   收藏代码
  1. User.username_or_first_name_like("ben")  

Make searching and ordering data in your application trivial 

差不多已经可以使用Searchlogic了,但是更精彩的还在这后面。如果仅仅提供上面这些model的接口,你要如何跟controllers和views结合起来使用?当然使用Searchlogic提供的这些接口比使用Rails本身的接口方便多了,但是还不够方便。 

Searchlogic另外提供了一个search方法,该方法接受一个hash,返回的是一个Searchlogic::Search对象。 
可以这样用: 
Ruby代码   收藏代码
  1. search = User.search(:username_like => "bjohnson":age_less_than => 20)  
  2. search.all  

上面的代码相当于: 
Ruby代码   收藏代码
  1. User.username_like("bjohnson").age_less_than(20).all  

这个Searchlogic::Search对象有点类似named scope,它也不会立即发起SQL查询。也可以进行链式的调用以添加搜索条件,也可以读取搜索条件。 
Ruby代码   收藏代码
  1. search.username_like                             # => "bjohnson"  
  2. search.age_gt = 2                                 #=> 2  
  3. search.id_gt(10).email_begins_with("bjohnson")   # => <#Searchlogic::Search...>  
  4. search.all                                        #=> An array of users  
  5. search.count                                      #=> integer  
  6. # .. 等等  


看起来似乎search方法更麻烦了些,但是这个hash……嗯,Controller中的params是个hash……想到了吧。 

ok,现在从Controller开始,controller就这么干净: 
Ruby代码   收藏代码
  1. class UsersController < ApplicationController  
  2.   def index  
  3.     @search = User.search(params[:search])  
  4.     @users = @search.all  
  5.   end  
  6. end  

页面是这样的(haml的代码,不明白可以当它是html.erb。什么是 haml): 
Haml代码   收藏代码
  1. - form_for @search do |f|  
  2.   = f.text_field :username_like  
  3.   = f.select :age_greater_than, (0..100)  
  4.   = f.text_field :orders_total_greater_than  
  5.   = f.submit  

searchlogic改写了form_for方法,使它能够认识Searchlogic::Search对象,并在参数为Searchlogic::Search对象时,把form的method转为get。来看看源码: 
Ruby代码   收藏代码
  1. # Automatically makes the form method :get if a Searchlogic::Search and sets  
  2. # the params scope to :search  
  3. def form_for(*args, &block)  
  4.   if search_obj = args.find { |arg| arg.is_a?(Searchlogic::Search) }  
  5.     options = args.extract_options!  
  6.     options[:html] ||= {}  
  7.     options[:html][:method] ||= :get  
  8.     options[:url] ||= url_for  
  9.     args.unshift(:searchif args.first == search_obj  
  10.     args << options  
  11.   end  
  12.   super  
  13. end  

另外SearchLogic还带了一个排序的order helper: 
Haml代码   收藏代码
  1. = order @search, :by => :age  
  2. = order @search, :by => :created_at, :as => "Created date"  

这会在面面上生成2个链接,效果如下图: 
 
看看表头第一列那个Order Date,一看就知道是干什么用的了  

利用现有的named scope 
如果你已经定义了这样的一个named scope: 
Ruby代码   收藏代码
  1. User.named_scope :four_year_olds:conditions => {:age => 4}  

可以这样用: 
Ruby代码   收藏代码
  1. User.search(:four_year_olds => true:username_like => "bjohnson")  

然后你的表单是这样的: 
Haml代码   收藏代码
  1. - form_for @search do |f|  
  2.   = f.text_field :username_like  
  3.   = f.check_box :four_year_olds  
  4.   = f.submit  


注意这里传了个true给named scope,如果原来定义的named scope不接受任何参数,可以在这里传个true或者false给它,如果传的是个false,那么这个named scope将被忽略。如果named scope接受参数,那么这个值会被当作参数传给named scope。 

分页: 
will_paginate结合使用,很简单: 
Ruby代码   收藏代码
  1. User.username_like("bjohnson").age_less_than(20).paginate(:page => params[:page])  
  2. User.search(:username_like => "bjohnson":age_less_than => 20).paginate(:page => params[:page])  



__END__ 
cookie: 
今天还发现一个好玩的小东西,叫faker,可以生成随机的姓名、email等等。蛮好玩的。 
Shell代码   收藏代码
  1. gem install faker  
  2. irb  
  3. require 'rubygems'  
  4. require 'faker'  
  5. Faker::Name.name  
  6. Faker::Name.name  
  7. Faker::Name.name  
  8. Faker::Internet.email  
  9. Faker::Internet.email  
  10. Faker::Internet.email  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值