第0章 目标
最近的一个项目中,需要在不同的页面实现搜索功能,之前有项目做过搜索功能,但没有认真总结,每次需要做这个功能时,还是需要去网上搜索,浪费时间,因此趁此机会,将这个功能的加入我的私人代码库,方便后续使用。
第1章 安装gems
在Gemfile中加入如下gems:
1 2 3 4
| gem ‘ransack’ gem ‘will_paginate’ gem 'will_paginate-bootstrap' gem ‘seo_helper’
|
执行 bundle install
备注:gem 'will_paginate-bootstrap'
用来美化分页效果的。
第2章 在相应的页面添加 View 代码
新建一个search_bar, touch app/views/jobs/_search_bar.html.erb
加入如下代码:
app/views/jobs/_search_bar.html.erb1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <div class="row"> <div class="col-sm-9 col-lg-8 col-lg-offset-2"> <%= form_tag search_jobs_path , :method => :get, :class => "jobs-search-form" do %> <div class="input-group"> <input type="text" class="form-control" name="q" value="<%= params[:q] %>" placeholder="搜索工作关键字..."> <span class="input-group-btn"> <button type="submit" class="btn btn-default"> <span class="glyphicon glyphicon-search"></span> </button> </span> </div> <% end %> </div>
|
第3章 在job/index页面增加search_bar
修改 views/jobs/index.html.erb,加入下列代码
1
| <%= render "jobs/search_bar" %>
|
第4章 修改jobs_controller.rb
修改jobs_controller.rb
,加入如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def search if @query_string.present? search_result = Job.ransack(@search_criteria).result(:distinct => true) @jobs = search_result.paginate(:page => params[:page], :per_page => 15 ) end end protected def validate_search_key @query_string = params[:q].gsub(/\\|\'|\/|\?/, "") if params[:q].present? @search_criteria = search_criteria(@query_string) end def search_criteria(query_string) { :title_cont => query_string } end
|
并在jobs_controller.rb里,加入如下代码
1
| before_action :validate_search_key, only: [:search]
|
这里补充两点:
(1)如果你后面不想增加search结果页面,可以继续使用index页面,但是上述search action部分代码要修改为:
1 2 3 4 5 6 7
| def search if @query_string.present? search_result = Job.ransack(@search_criteria).result(:distinct => true) @jobs = search_result.paginate(:page => params[:page], :per_page => 15 ) end render :index end
|
上述代码其实还可以伪造一个空的@jobs以便处理搜索没有值的情况,比如在if语句前加入@jobs = Job.where(id:-1)
(2)ransack是用hash(字典)的key, value,来实现模糊搜索功能的,而key的可以分为两部分,前一部分是字段组合,后一部分是搜索前缀。
目前我的Job model里面只有title,description等几个字段,这次我只实现title字段模糊查询,
所以我构造了一个{ :title_cont => query_string }
。
如果我想是想title,description(多字段)字段模糊查询,则需要改为
{ :title_or_description_cont => query_string }
第5章 修改routes.rb
修改routes.rb,加入search action
1 2 3 4 5
| resources :jobs do collection do get :search end end
|
第6章 新增搜索页面
新增搜索页面,touch app/views/jobs/search.html.erb
,加入如下代码
app/views/jobs/search.html.erb1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <div class="panel panel-default col-md-10 col-md-offset-1"> <div class="panel-body"> <div class="group"> <div class="row"> <div class="col-sm-2 col-lg-1 "> </div> <%= render :partial => "jobs/search_bar" %> </div> </div>
<br> <% if @query_string.blank? %> <h4 class="search-info-title">搜索信息不能为空,请输入关键字搜索</h4> <% elsif @jobs.blank? %> <br> <h4 class="search-info-title">亲,没有搜索到相关工作信息哦,要不换个关键词试试?</h4> <% else %> <h4 class="search-info-title"> 有关"<%= @query_string %>"的工作信息 </h4> <hr>
<div class="search-result">
<% @jobs.each do |job| %> <div class="job-item"> <p><span><%= job.publisher %></span><span class="pull-right">更新于 <%= job.updated_at %></span></p> <h4><%= link_to(render_highlight_content(job,@query_string), job_path(job)) %></h4> <p><i class="fa fa-street-view" aria-hidden="true"></i> <%= job.city %></p> <p><i class="fa fa-clock-o" aria-hidden="true"></i> <%= job.deadline %></p> <p><span class="label label-success"><%= t(job.category) %></span></p> <hr> </div> <% end %> </div> <% if @jobs.present? %> <div class="text-center"> <%= will_paginate(@jobs, renderer: BootstrapPagination::Rails) %> </div> <% end %> <% end %> </div> </div>
|
上述代码请根据你的job的实际属性来修改。
PS:如果想修改分页按钮的名称,将代码
1
| <%= will_paginate @jobs, renderer: BootstrapPagination::Rails %>
|
修改为:
1
| <%= will_paginate @jobs, renderer: BootstrapPagination::Rails, :previous_label => t('上一页'), :next_label => t('下一页') %>
|
第7张 实现搜索结果高亮
由于我只搜索title这一个字段,所以这里我使用了一种讨巧的方法,即使用seo的方式来实现单个关键字高亮显示。
需要注意的是这种方式不能同时显示多个高亮关键字,比如同时显示title和descrpiton中匹配到的关键字。
思路:
实作一个高亮显示的helper方法,然后在搜索结果页面调用这个helper方法,其中传入两个参数,分别是资料的model名和在搜索栏中输入的关键词,并设置高亮显示的范围。
在app/helpers/jobs_helper.rb
里添加如下代码
1 2 3 4 5 6 7
| def render_highlight_content(job,query_string) excerpt_cont = excerpt(job.title, query_string, radius: 500) highlight(excerpt_cont, query_string) end
|
在搜索结果页面调用高亮显示功能的helper方法
在app/views/jobs/search.html.erb
里修改代码<%= link_to(job.title,job_path(job)) %>
,
将其改为<%= link_to(render_highlight_content(job,@query_string),job_path(job)) %>
第8章 结束语
至此,简单的搜索功能完成,但是这只是基础的方法,更多优秀方法等待挖掘。下面是我的成果: