美文网首页编程豆知识
ROR豆知识: 使用 ransack 实现搜索功能

ROR豆知识: 使用 ransack 实现搜索功能

作者: Kerzzi | 来源:发表于2018-01-21 12:31 被阅读43次

第0章 目标

最近的一个项目中,需要在不同的页面实现搜索功能,之前有项目做过搜索功能,但没有认真总结,每次需要做这个功能时,还是需要去网上搜索,浪费时间,因此趁此机会,将这个功能的加入我的私人代码库,方便后续使用。

第1章 安装gems

在Gemfile中加入如下gems:

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

加入如下代码:

<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>
</div>

第3章 在job/index页面增加search_bar

修改 views/jobs/index.html.erb,加入下列代码

 <%= render "jobs/search_bar" %>

第4章 修改jobs_controller.rb

修改jobs_controller.rb,加入如下代码

 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里,加入如下代码

 before_action :validate_search_key, only: [:search]

这里补充两点:
(1)如果你后面不想增加search结果页面,可以继续使用index页面,但是上述search action部分代码要修改为:

  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

 resources :jobs do
    collection do
      get :search
    end
 end

第6章 新增搜索页面

新增搜索页面,touch app/views/jobs/search.html.erb,加入如下代码

<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:如果想修改分页按钮的名称,将代码

<%= will_paginate @jobs, renderer: BootstrapPagination::Rails %>

修改为:

 <%= 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里添加如下代码

  #定义高亮显示功能的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章 结束语

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

job.gif

相关文章

网友评论

    本文标题:ROR豆知识: 使用 ransack 实现搜索功能

    本文链接:https://www.haomeiwen.com/subject/clvfaxtx.html