أنا أعتبر الكشاف "تم" . ليس لديها أي تبعيات إنتاجية، لذلك لا يوجد سبب يمنعها من العمل إلى أجل غير مسمى. لقد انتقلت أيضًا إلى أشياء أخرى.
إذا وجدت خطأ ما، فلا تتردد في فتح مشكلة حتى يتمكن الآخرون من العثور عليها ومناقشتها، ولكن من غير المرجح أن أرد عليها شخصيًا. إذا لم يعد Searchlight يلبي احتياجاتك بعد الآن، فابتعد! :)
يعد Searchlight طريقة منخفضة السحر لإنشاء عمليات بحث في قاعدة البيانات باستخدام ORM.
يمكن أن يعمل Searchlight مع أي ORM أو كائن يمكنه إنشاء استعلام باستخدام استدعاءات الأساليب المتسلسلة (على سبيل المثال، ActiveRecord's .where(...).where(...).limit(...)
أو سلاسل مماثلة مع Sequel، Mongoid ، إلخ).
يتوفر تطبيق تجريبي ورمز هذا التطبيق لمساعدتك على البدء.
الاستخدام الرئيسي لـ Searchlight هو دعم نماذج البحث في تطبيقات الويب.
Searchlight لا يكتب الاستعلامات لك. ما يفعله هو:
form_for
في Rails)WHERE first_name =
الجزء) على سبيل المثال، إذا كان لديك فئة بحث 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
الخاصة بالفئة الفائقة وتعديلها:
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
تجري اختبارات الطفرة باستخدام متحولة.
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)