文章目录
  1. 1. 第0章 目标
  2. 2. 第1章 安装gems
  3. 3. 第2章 在相应的页面添加 View 代码
  4. 4. 第3章 在job/index页面增加search_bar
  5. 5. 第4章 修改jobs_controller.rb
  6. 6. 第5章 修改routes.rb
  7. 7. 第6章 新增搜索页面
  8. 8. 第7张 实现搜索结果高亮
  9. 9. 第8章 结束语

第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.erb
1
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
# 取到params[:q]的内容并去掉非法的内容
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.erb
1
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
#定义高亮显示功能的helper方法
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章 结束语

至此,简单的搜索功能完成,但是这只是基础的方法,更多优秀方法等待挖掘。下面是我的成果:

文章目录
  1. 1. 第0章 目标
  2. 2. 第1章 安装gems
  3. 3. 第2章 在相应的页面添加 View 代码
  4. 4. 第3章 在job/index页面增加search_bar
  5. 5. 第4章 修改jobs_controller.rb
  6. 6. 第5章 修改routes.rb
  7. 7. 第6章 新增搜索页面
  8. 8. 第7张 实现搜索结果高亮
  9. 9. 第8章 结束语