我認為探照燈「完成」了。它沒有生產依賴性,因此沒有理由它不應該無限期地工作。我也轉向了其他事情。
如果您發現錯誤,請隨時提出問題,以便其他人可以找到它並進行討論,但我不太可能親自回覆。如果 Searchlight 不再滿足您的需求,請放棄! :)
Searchlight 是一種使用 ORM 建立資料庫搜尋的低魔法方法。
Searchlight 可以使用任何可以使用鍊式方法呼叫建構查詢的 ORM 或物件(例如,ActiveRecord 的.where(...).where(...).limit(...)
或 Sequel、Mongoid 的類似鏈, ETC)。
演示應用程式和該應用程式的程式碼可協助您入門。
Searchlight 的主要用途是支援 Web 應用程式中的搜尋表單。
Searchlight 不會為您編寫查詢。它的作用是:
form_for
)WHERE first_name =
部分)例如,如果您有一個名為YetiSearch
的 Searchlight 搜尋類,並且您可以像這樣實例化它:
search = YetiSearch . new (
# or params[:yeti_search]
"active" => true , "name" => "Jimmy" , "location_in" => %w[ NY LA ]
)
....呼叫search.results
將透過呼叫YetiSearch
上的search_active
、 search_name
和search_location_in
方法來建立搜索,假設您已經定義了它們。 (如果您再次執行此操作但省略"name"
,則不會呼叫search_name
。)
然後, results
方法將傳回最後一個搜尋方法的回傳值。如果您使用的是 ActiveRecord,這將是一個ActiveRecord::Relation
,然後您可以呼叫each
來循環結果, to_sql
來取得產生的查詢等。
搜尋類別有兩個主要部分: base_query
和一些search_
方法。例如:
class PersonSearch < Searchlight :: Search
# This is the starting point for any chaining we do, and it's what
# will be returned if no search options are passed.
# In this case, it's an ActiveRecord model.
def base_query
Person . all # or `.scoped` for ActiveRecord 3
end
# A search method.
def search_first_name
# If `"first_name"` was the first key in the options_hash,
# `query` here will be the base query, namely, `Person.all`.
query . where ( first_name : options [ :first_name ] )
end
# Another search method.
def search_last_name
# If `"last_name"` was the second key in the options_hash,
# `query` here will be whatever `search_first_name` returned.
query . where ( last_name : last_name )
end
end
呼叫PersonSearch.new("first_name" => "Gregor", "last_name" => "Mendel").results
將執行Person.all.where(first_name: "Gregor").where(last_name: "Mendel")
並傳回產生的ActiveRecord::Relation
。如果您省略了last_name
選項,或提供了"last_name" => ""
,則不會新增第二個where
。
這是一個更完整的範例搜尋類別。請注意,由於 Searchlight 不會為您編寫查詢,因此您可以自由地執行 ORM 支援的任何操作。 (請參閱spec/support/book_search.rb
了解更多奇特之處。)
# app/searches/city_search.rb
class CitySearch < Searchlight :: Search
# `City` here is an ActiveRecord model
def base_query
City . includes ( :country )
end
# Reach into other tables
def search_continent
query . where ( '`countries`.`continent` = ?' , continent )
end
# Other kinds of queries
def search_country_name_like
query . where ( "`countries`.`name` LIKE ?" , "% #{ country_name_like } %" )
end
# .checked? considers "false", 0 and "0" to be false
def search_is_megacity
query . where ( "`cities`.`population` #{ checked? ( is_megacity ) ? '>=' : '<' } ?" , 10_000_000 )
end
end
以下是一些搜尋範例。
CitySearch . new . results . to_sql
# => "SELECT `cities`.* FROM `cities` "
CitySearch . new ( "name" => "Nairobi" ) . results . to_sql
# => "SELECT `cities`.* FROM `cities` WHERE `cities`.`name` = 'Nairobi'"
CitySearch . new ( "country_name_like" => "aust" , "continent" => "Europe" ) . results . count # => 6
non_megas = CitySearch . new ( "is_megacity" => "false" )
non_megas . results . to_sql
# => "SELECT `cities`.* FROM `cities` WHERE (`cities`.`population` < 10000000"
non_megas . results . each do | city |
# ...
end
對於您定義的每個搜尋方法,Searchlight 將定義對應的選項讀取器方法。例如,如果您新增def search_first_name
,您的搜尋類別將獲得一個.first_name
方法,該方法傳回options["first_name"]
,或者,如果該鍵不存在, options[:first_name]
。這主要在建立表單時有用。
由於它認為鍵"first_name"
和:first_name
是可以互換的,因此如果您同時提供這兩個鍵,Searchlight 將引發錯誤。
Searchlight 提供了一些方法來檢查為您的搜尋提供的選項。
raw_options
包含了它被實例化的確切內容options
包含所有非空的raw_options
empty?
。例如,如果raw_options
是categories: nil, tags: ["a", ""]
,則選項將是tags: ["a"]
。empty?(value)
對於nil
、純空白字串或從value.empty?
(例如,空數組)checked?(value)
傳回一個布林值,其運作原理與!!value
類似,但將0
、 "0"
和"false"
視為false
最後, explain
將告訴您 Searchlight 如何解釋您的選項。例如, book_search.explain
可能輸出:
Initialized with `raw_options`: ["title_like", "author_name_like", "category_in",
"tags", "book_thickness", "parts_about_lolcats"]
Of those, the non-blank ones are available as `options`: ["title_like",
"author_name_like", "tags", "book_thickness", "in_print"]
Of those, the following have corresponding `search_` methods: ["title_like",
"author_name_like", "in_print"]. These would be used to build the query.
Blank options are: ["category_in", "parts_about_lolcats"]
Non-blank options with no corresponding `search_` method are: ["tags",
"book_thickness"]
有時,使用預設搜尋選項很有用 - 例如,「尚未履行的訂單」或「上個月列出的房屋」。
這可以透過覆蓋options
來完成。例如:
class BookSearch < SearchlightSearch
# def base_query...
def options
super . tap { | opts |
opts [ "in_print" ] ||= "either"
}
end
def search_in_print
return query if options [ "in_print" ] . to_s == "either"
query . where ( in_print : checked? ( options [ "in_print" ] ) )
end
end
您可以對現有搜尋類別進行子類化,並使用不同的基本查詢支援所有相同的選項。例如,這對於單表繼承可能很有用。
class VillageSearch < CitySearch
def base_query
Village . all
end
end
或者你可以使用super
來取得超類別的base_query
值並修改它:
class SmallTownSearch < CitySearch
def base_query
super . where ( "`cities`.`population` < ?" , 1_000 )
end
end
您可以提供探照燈搜尋任何您喜歡的選項;只有那些具有匹配的search_
方法的人才能確定要運行哪些方法。例如,如果您想要執行AccountSearch.new("super_user" => true)
來尋找受限結果,只需確保在建置查詢時檢查options["super_user"]
即可。
Searchlight 與 Rails 表單配合得很好 - 只需包含ActionView
適配器,如下所示:
require "searchlight/adapters/action_view"
class MySearch < Searchlight :: Search
include Searchlight :: Adapters :: ActionView
# ...etc
end
這將允許使用Searchlight::Search
和form_for
:
# app/views/cities/index.html.haml
...
= form_for ( @search , url : search_cities_path ) do | f |
% fieldset
= f . label :name , "Name"
= f . text_field :name
% fieldset
= f . label :country_name_like , "Country Name Like"
= f . text_field :country_name_like
% fieldset
= f . label :is_megacity , "Megacity?"
= f . select :is_megacity , [ [ 'Yes' , true ] , [ 'No' , false ] , [ 'Either' , '' ] ]
% fieldset
= f . label :continent , "Continent"
= f . select :continent , [ 'Africa' , 'Asia' , 'Europe' ] , include_blank : true
= f . submit "Search"
- @results . each do | city |
= render partial : 'city' , locals : { city : city }
只要您的表單提交了您的搜尋可以理解的選項,您就可以輕鬆地將其連接到控制器中:
# app/controllers/orders_controller.rb
class OrdersController < ApplicationController
def index
@search = OrderSearch . new ( search_params ) # For use in a form
@results = @search . results # For display along with form
end
protected
def search_params
# Ensure the user can only browse or search their own orders
( params [ :order_search ] || { } ) . merge ( user_id : current_user . id )
end
end
對於任何給定版本,請檢查.travis.yml
以了解我們正在測試相容性的 Ruby 版本。
將此行新增至應用程式的 Gemfile 中:
gem 'searchlight'
然後執行:
$ bundle
或自己安裝:
$ gem install searchlight
rake
運行測試; rake mutant
使用突變體執行突變測試。
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)