Isnor Creative
Isnor Creative Blog
Ruby, Ruby on Rails, Ember, Elm, Phoenix, Elixir, React, Vue

Feb 1, 2015

Ember.js, Ruby on Rails advanced Search with Ransack Part II

I wrote previously, when I was first beginning to learn Ember, about my efforts to incorporate advanced search into an application, using Ransack in my Ruby on Rails API.

I’ve continued to work on this, and have now added Ember’s query params– which at the time were just coming out – into the mix, so that I can present each search criterion as a removable filter.

I did this using mixins and a view, because I have the same functionality in a series of sections, but I have simplified it here.

Image we’re talking about a section of the application devoted to widgets…

In the widgets template, I am displaying a series of filters based on the query params, which map to Ransack search criteria.

Clicking the list item invokes the removeRansackParam action, which will be handled by the widgets controller.

app/templates/widgets.hbs:

{{#if ransacked}}
  <ul class="filters">
    {{#each ransacked}}
        {{#if value}}
            <li {{action 'removeRansackParam' key}}>
                <span class="glyphicon glyphicon-remove-circle"></span>
                {{label}} {{value}}
            </li>
        {{/if}}
    {{/each}}
  </ul>
{{/if}}

The widets route specifies a q query param, when that query param changes, the model is refreshed. If query params are found if uses them, and sets ransack based on parsing the query params into a hash.

app/routes/widgets.coffee:

`import Ember from "ember"`
WidgetsRoute = Ember.Route.extend(
  ransack: null 
  queryParams:
    q:
      refreshModel: true

  setupController: (controller, model)->
    controller.set('model', model)
    controller.set('ransack', @ransack)

  getRansackHash: (params)->
    search = params.q.split("&")
    hash = {}
    search.forEach((el)->
      item = el.split(/\=(.+)?/)
      key = item[0]
      value = item[1]
      hash[key] = value
     )
     return hash            

  model: (params)-> 
    if params.q
      @set('ransack', @getRansackHash(params))
      @store.find "widget", {q: @get('ransack')}
    else
      @set('ransack', null)
      @store.find "widget"
)   
`export default WidgetsRoute`

The widgets controller has a ransacked property which updates when ransack updates, this is taking the ransack hash and converting it to an array that can be itereated over by Handlebars, as Ember’s version of Handlebars cannot iterate over a hash, to the best of my knowledge.

Here as well the removeRansackParam action handles clicks on any of the indivual filters. This removes the filter and then transitions to the updated query params.

app/controllers/widgets.coffee:

`import Ember from "ember"`

WidgetsController = Ember.ArrayController.extend(RansackIndexMixin)
  queryParams: ['q']
  q: null
  ransack: null

    ransacked: (->
      r = @get('ransack')
      array = []
      if r
        for k,v of r
          label = k.split('_cont')[0] # this should be improved
          array.push({key: k, value: v, label: label})
        return array
    ).property('ransack')   

    actions:

        removeRansackParam: (key) ->
          delete @ransack[key] 
          p = Ember.$.param @get('ransack')
          @transitionToRoute(queryParams: {q: p})
          false

`export default WidgetsController`

The search controller and is where the search is initially performed. This is backing a search template which is where the form fields for the Ransack search are located. This controller has two actions – one for performing the search, and the other for resetting the search.

app/controllers/widget/search.coffee:

`import Ember from "ember"`

WidgetsSearchController = Ember.Controller.extend(
    needs: "widgets"
    params: {}

    actions:

      search: ->
        if @get('params')
          p = Ember.$.param @get('params')
          @transitionToRoute('widgets', queryParams:{q: p})

      reset_search: ->
        @transitionToRoute('widgets', queryParams: {q:null})
)
`export default WidgetsSearchController`

app/templates/widgets/search.hbs

<form>
  {{input value=params.title_cont}}
  <button {{action "search"}}>Filter</button>
  <button {{action "reset_search"}}>Reset</button>
</form>

I am available for Ember and Ruby on Rails consulting work – get in touch to learn more.

Gordon B. Isnor

Gordon B. Isnor writes about Ruby on Rails, Ember.js, Elm, Elixir, Phoenix, React, Vue and the web.
If you enjoyed this article, you may be interested in the occasional newsletter.

I am now available for project work. I have availability to build greenfield sites and applications, to maintain and update/upgrade existing applications, team augmentation. I offer website/web application assessment packages that can help with SEO/security/performance/accessibility and best practices. Let’s talk

comments powered by Disqus