サーチライトは「完成」したと思います。運用環境への依存関係がないため、無期限に動作しない理由はありません。他のことにも移りました。
バグを見つけた場合は、他の人が見つけて議論できるように、遠慮なく問題を開いてください。ただし、私が個人的に応答することはほとんどありません。 Searchlight がニーズを満たさなくなった場合は、フォークをやめてください。 :)
Searchlight は、ORM を使用してデータベース検索を構築するための魔法のような方法です。
Searchlight は、チェーンされたメソッド呼び出し(例: ActiveRecord の.where(...).where(...).limit(...)
、または Sequel、Mongoid を使用した同様のチェーン) を使用してクエリを構築できる任意の ORM またはオブジェクトと連携できます。 、など)。
デモ アプリとそのアプリのコードは、開始に役立つものとして利用できます。
Searchlight の主な用途は、Web アプリケーションで検索フォームをサポートすることです。
サーチライトはクエリを作成しません。それが行うことは次のとおりです。
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
呼び出して生成されたクエリを取得したりできます。
search クラスには、 base_query
といくつかのsearch_
メソッドという 2 つの主要な部分があります。例えば:
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" => ""
を指定した場合、2 番目の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
を追加すると、検索クラスはoptions["first_name"]
を返す.first_name
メソッドを取得します。そのキーが存在しない場合はoptions[:first_name]
返します。これは主にフォームを構築する場合に役立ちます。
Searchlight はキー"first_name"
と:first_name
交換可能であると見なすため、両方を指定するとエラーが発生します。
Searchlight には、検索に提供されたオプションを調べるためのいくつかの方法が用意されています。
raw_options
は、インスタンス化された内容が正確に含まれますoptions
空ではなかったすべてのraw_options
含まれていますかempty?
。たとえば、 raw_options
がcategories: nil, tags: ["a", ""]
の場合、オプションはtags: ["a"]
になります。empty?(value)
nil
、空白のみの文字列、またはvalue.empty?
から true を返すその他のものに対して true を返します。 (例: 空の配列)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
Searchlight 検索には、任意のオプションを指定できます。一致する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
これにより、 form_for
でSearchlight::Search
を使用できるようになります。
# 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
mutant を使用して突然変異テストを実行します。
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)