Saya menganggap lampu sorot "selesai" . Ia tidak memiliki ketergantungan produksi, jadi tidak ada alasan ia tidak berfungsi tanpa batas waktu. Saya juga telah beralih ke hal lain.
Jika Anda menemukan bug, jangan ragu untuk membuka masalah sehingga orang lain dapat menemukannya dan mendiskusikannya, namun saya tidak akan menanggapinya secara pribadi. Jika Searchlight tidak lagi memenuhi kebutuhan Anda, keluarlah! :)
Searchlight adalah cara yang tidak terlalu ajaib untuk membangun pencarian database menggunakan ORM.
Searchlight dapat bekerja dengan ORM atau objek apa pun yang dapat membuat kueri menggunakan pemanggilan metode berantai (misalnya, .where(...).where(...).limit(...)
, atau rantai serupa dengan Sekuel, Mongoid , dll).
Aplikasi demo dan kode untuk aplikasi tersebut tersedia untuk membantu Anda memulai.
Kegunaan utama Searchlight adalah untuk mendukung formulir pencarian di aplikasi web.
Searchlight tidak menulis pertanyaan untuk Anda. Apa yang dilakukannya adalah:
form_for
di Rails)WHERE first_name =
) Misalnya, jika Anda memiliki kelas pencarian Searchlight bernama YetiSearch
, dan Anda membuat instance seperti ini:
search = YetiSearch . new (
# or params[:yeti_search]
"active" => true , "name" => "Jimmy" , "location_in" => %w[ NY LA ]
)
... memanggil search.results
akan membangun pencarian dengan memanggil metode search_active
, search_name
, dan search_location_in
pada YetiSearch
Anda, dengan asumsi Anda telah mendefinisikannya. (Jika Anda melakukannya lagi tetapi menghilangkan "name"
, itu tidak akan memanggil search_name
.)
Metode results
kemudian akan mengembalikan nilai kembalian dari metode pencarian terakhir. Jika Anda menggunakan ActiveRecord, ini akan menjadi ActiveRecord::Relation
, dan Anda kemudian dapat memanggil each
untuk mengulang hasil, to_sql
untuk mendapatkan kueri yang dihasilkan, dll.
Kelas pencarian memiliki dua bagian utama: base_query
dan beberapa metode search_
. Misalnya:
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
Memanggil PersonSearch.new("first_name" => "Gregor", "last_name" => "Mendel").results
akan menjalankan Person.all.where(first_name: "Gregor").where(last_name: "Mendel")
dan kembali hasil ActiveRecord::Relation
. Jika Anda menghilangkan opsi last_name
, atau memberikan "last_name" => ""
, where
kedua tidak akan ditambahkan.
Berikut contoh kelas pencarian yang lebih lengkap. Perhatikan bahwa karena Searchlight tidak menulis kueri untuk Anda, Anda bebas melakukan apa pun yang didukung ORM Anda . (Lihat spec/support/book_search.rb
untuk lebih menarik lagi.)
# 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
Berikut beberapa contoh pencarian.
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
Untuk setiap metode pencarian yang Anda tentukan, Searchlight akan menentukan metode pembaca opsi yang sesuai. Misalnya, jika Anda menambahkan def search_first_name
, kelas pencarian Anda akan mendapatkan metode .first_name
yang mengembalikan options["first_name"]
atau, jika kunci tersebut tidak ada, options[:first_name]
. Ini berguna terutama saat membuat formulir.
Karena menganggap kunci "first_name"
dan :first_name
dapat dipertukarkan, Searchlight akan memunculkan kesalahan jika Anda menyediakan keduanya.
Searchlight menyediakan beberapa metode untuk memeriksa opsi yang disediakan untuk pencarian Anda.
raw_options
berisi persis apa yang dipakaioptions
berisi semua raw_options
yang tidak empty?
. Misalnya, jika raw_options
adalah categories: nil, tags: ["a", ""]
, opsinya adalah tags: ["a"]
.empty?(value)
mengembalikan nilai true untuk nil
, string khusus spasi, atau apa pun yang mengembalikan nilai true dari value.empty?
(misalnya, array kosong)checked?(value)
mengembalikan boolean, yang sebagian besar berfungsi seperti !!value
tetapi menganggap 0
, "0"
, dan "false"
sebagai false
Terakhir, explain
akan memberi tahu Anda bagaimana Searchlight menafsirkan pilihan Anda. Misalnya, book_search.explain
mungkin menghasilkan:
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"]
Terkadang berguna untuk memiliki opsi pencarian default - misalnya, "pesanan yang belum dipenuhi" atau "rumah terdaftar dalam sebulan terakhir".
Hal ini dapat dilakukan dengan mengesampingkan options
. Misalnya:
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
Anda dapat membuat subkelas kelas pencarian yang ada dan mendukung semua opsi yang sama dengan kueri dasar yang berbeda. Ini mungkin berguna untuk pewarisan tabel tunggal, misalnya.
class VillageSearch < CitySearch
def base_query
Village . all
end
end
Atau Anda dapat menggunakan super
untuk mendapatkan nilai base_query
superkelas dan memodifikasinya:
class SmallTownSearch < CitySearch
def base_query
super . where ( "`cities`.`population` < ?" , 1_000 )
end
end
Anda dapat memberikan pencarian Searchlight opsi apa pun yang Anda suka; hanya mereka yang memiliki metode search_
yang cocok yang akan menentukan metode apa yang dijalankan. Misalnya, jika Anda ingin melakukan AccountSearch.new("super_user" => true)
untuk menemukan hasil yang dibatasi, pastikan Anda mencentang options["super_user"]
saat membuat kueri Anda.
Searchlight berfungsi baik dengan formulir Rails - cukup sertakan adaptor ActionView
sebagai berikut:
require "searchlight/adapters/action_view"
class MySearch < Searchlight :: Search
include Searchlight :: Adapters :: ActionView
# ...etc
end
Ini akan mengaktifkan penggunaan Searchlight::Search
dengan 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 }
Selama opsi pengiriman formulir Anda dipahami oleh pencarian Anda, Anda dapat dengan mudah menghubungkannya ke pengontrol Anda:
# 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
Untuk versi tertentu, periksa .travis.yml
untuk melihat versi Ruby apa yang kami uji kompatibilitasnya.
Tambahkan baris ini ke Gemfile aplikasi Anda:
gem 'searchlight'
Dan kemudian jalankan:
$ bundle
Atau instal sendiri sebagai:
$ gem install searchlight
rake
menjalankan tes; rake mutant
menjalankan tes mutasi menggunakan mutan.
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)