ฉันถือว่า searchlight "เสร็จสิ้น" ไม่มีการพึ่งพาการผลิต ดังนั้นจึงไม่มีเหตุผลที่จะไม่ทำงานอย่างไม่มีกำหนด ฉันยังได้ย้ายไปทำสิ่งอื่นด้วย
หากคุณพบข้อบกพร่อง คุณสามารถเปิดปัญหาเพื่อให้ผู้อื่นค้นพบและหารือได้ แต่ฉันไม่น่าจะตอบกลับเป็นการส่วนตัว หาก Searchlight ไม่ตรงกับความต้องการของคุณอีกต่อไป ให้แยกออกไป! -
Searchlight เป็นวิธีที่ไม่ซับซ้อนในการสร้างการค้นหาฐานข้อมูลโดยใช้ ORM
Searchlight สามารถทำงานร่วมกับ ORM หรือวัตถุ ใดๆ ที่สามารถสร้างแบบสอบถามโดยใช้ การเรียกเมธอดแบบลูกโซ่ (เช่น ActiveRecord's .where(...).where(...).limit(...)
หรือลูกโซ่ที่คล้ายกันกับ Sequel, Mongoid ฯลฯ)
มีแอปสาธิตและโค้ดสำหรับแอปนั้นเพื่อช่วยคุณในการเริ่มต้น
การใช้งานหลักของ Searchlight คือการสนับสนุนแบบฟอร์มการค้นหาในเว็บแอปพลิเคชัน
Searchlight จะไม่เขียนข้อความค้นหาให้คุณ มันทำอะไร:
form_for
ใน Rails)WHERE first_name =
part) ตัวอย่างเช่น หากคุณมีคลาสการค้นหา Searchlight ชื่อ YetiSearch
และคุณสร้างอินสแตนซ์เช่นนี้:
search = YetiSearch . new (
# or params[:yeti_search]
"active" => true , "name" => "Jimmy" , "location_in" => %w[ NY LA ]
)
... การเรียก search.results
จะสร้างการค้นหาโดยการเรียกเมธอด search_active
, search_name
และ search_location_in
บน YetiSearch
ของคุณ โดยสมมติว่าคุณได้กำหนดไว้ (หากทำอีกครั้งแต่ไม่ใส่ "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)
ส่งคืน true สำหรับ nil
สตริงเฉพาะช่องว่าง หรือสิ่งอื่นใดที่คืนค่า true จาก 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
ของ superclass และแก้ไข:
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
สิ่งนี้จะเปิดใช้งานโดยใช้ 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
รันการทดสอบการกลายพันธุ์โดยใช้ mutant
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)