搜索是任何項目中必不可少的一項功能。在大多數(shù)應(yīng)用場景中,由于需要檢索的條件并不多,我們可以方便地使用get請求結(jié)合一些搜索類的gem(比如ransack)拢锹,輕松實現(xiàn)搜索功能,再配合will_paginate實現(xiàn)分頁功能萄喳。
但是卒稳,對于一些高級搜索頁面,往往會出現(xiàn)特殊的需求他巨,比如:
1.搜索的條件數(shù)量非常多——此時繼續(xù)用get請求來搜索充坑,會導(dǎo)致url過長而報錯(不同瀏覽器支持的url最大長度也不一樣);
2.需要在多張表之間join查詢——不能的搜索條件需要join不同的表染突,如果一次性全部join捻爷,效率必然很低。根據(jù)不同搜索條件來針對性地join份企,可提升搜索效率也榄;
3.需要優(yōu)化搜索代碼來提升搜索速度——比如搜索省份城市,需要對獲取的搜索數(shù)據(jù)進行處理分解司志;
4.需要搜索的字段甜紫,需要在數(shù)據(jù)庫中拼接幾個字段后再比較——比如搜索一個電話號碼,數(shù)據(jù)表中的電話號碼分為區(qū)號骂远、號碼囚霸、分機三個字段存儲,如果需要實現(xiàn)電話號碼的模糊搜索激才,必然需要用到類似于mysql中的concat功能拓型;
5.分頁問題——will_paginate默認只提供get方式的分頁额嘿,需要自己手動改造;
想要克服上述五個問題劣挫,就需要自己手動來寫搜索册养,以下是針對上述五個問題的我個人的解決方案:
1.改用post提交——post提交不會出現(xiàn)url過長的問題,比如原來的一個index頁压固,系統(tǒng)默認的路由捕儒,如果用post,會自動識別成create動作邓夕,此時有兩個方法解決,棄用index阎毅,自己建一個比如list的action焚刚,定義為post,避開系統(tǒng)的自動識別扇调;如果繼續(xù)想用ndex矿咕,如果快速搜索也需要用到get的index,則可以:
def index
list
end
然后
def index
xxxx
render template: "/xxx/index"
end
2.手動寫搜索代碼狼钮,判斷每個查詢參數(shù)是否被賦值碳柱,比如只有當(dāng)params[:province_ids]存在并有指時,才去join provinces表熬芜。搜索最終取決于三個變量 sql(拼接的sql語句)莲镣、joins(拼接的join語句)以及傳過來的搜索參數(shù)。sql和joins是兩個空數(shù)組涎拉,當(dāng)某個搜索參數(shù)有值時瑞侮,相應(yīng)地想這兩個數(shù)組push sql和join語句,最后通過下面的代碼實現(xiàn)搜索功能:
@objects = Example::Object.where([sql,@q]).joins(joins).paginate(per_page:20,page:params[:page])
3.對于省份城市的搜索鼓拧,由于省份城市可分為好幾級半火,比如區(qū)域(華東、華北季俩、華西钮糖、華南),省份(34個省級行政區(qū))酌住,和每個省份下的二級城市店归。我們可以同時搜索區(qū)域、省份赂韵、城市娱节。如果為了寫代碼方便,統(tǒng)一分解成二級城市來搜索祭示,那where city_id in (city_ids_string)機會非常長肄满,導(dǎo)致搜索效率很低谴古。因此需要分解。我的解決方案是:無論搜索哪一級稠歉,都將其id拼接成:“區(qū)域id_省份id_城市id”的格式掰担,如果只搜區(qū)域,則后面兩位都是0怒炸。比如光搜區(qū)域的带饱,歸入@region數(shù)組中,搜到省份的阅羹,無視區(qū)域其區(qū)域勺疼,直接歸入@province數(shù)組中,搜到二級城市的捏鱼,無視其區(qū)域和省份执庐,直接歸入@city中。通過分解导梆,最終可以得到這樣的搜索代碼:
where (region_id in @region or province_id in @province or city_id in @city)
4.這個問題相對好解決轨淌,直接使用使用數(shù)據(jù)庫的拼接字符串功能:
where concat(region_number, phone_number, ext_number) like '%xxx%'
5.這個問題我的解決方案是用jquery來重寫分頁鏈接的點擊事件,然后再頁面中設(shè)定一個隱藏的表單看尼,表單里有兩個隱藏的input递鹉,一個存儲上一次高級搜索所有的搜索參數(shù)(比如params[:q]),并且壓縮成json藏斩。還有一個就是page參數(shù)躏结。當(dāng)點擊分頁鏈接時,用jquery去取出這個分頁鏈接的page參數(shù)灾茁,然后賦值給表單中的page的input窜觉,最后以post形式再次提交表單(別忘了最后需要return false來阻止本身分頁鏈接功能)
至此,關(guān)于上述遇到的5個問題北专,我都給出了相應(yīng)的解決方案禀挫,可能不是優(yōu)秀的解決方案,但的確可以解決眼前的問題拓颓,歡迎大家一起討論或給出更加優(yōu)秀的解決方案语婴。