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.