Let me quickly introduce WiceGrid, if you do not know yet: it is a super-gem that will allow you to easily show a list/grid of items, and allow easy filtering/searching/pagination.
For rails there is, afaik, no better alternative. There are some javascript/jquery driven dynamic grids, but for me the big advantage is that with WiceGrid all work is done server-side, which is ideal when handling large sets of data.
Since you can just render html in any column, we do for instance the following for our KLIP platform :
In our first we show our internal identifier, and the external identifier. In code this looks like this:
g.column name: 'Id', in_csv: false do |pr|
render 'title_with_info', plan_request: pr
end
and the partial title_with_info
looks like
%h4
= plan_request.ident
%p.text-muted.small
= plan_request.maprequest_id
But now the problem is: how can we, when filtering, automatically look for both fields? WiceGrid automatically handles one field, but not both. Luckily, WiceGrid allows us to define custom filter types. What we want is:
- we want the filter to just look like a standard string field
- we want to build a query which will search for
ident
ormaprequest_id
.
Adding your own custom filter types is not entirely clear in the documentation, I had to take a look at the code to fully understand it. So that's why I decided to write it in detail here.
It takes three steps:
- define a class to create the correct filter (a conditions generator)
- define a custom filter_type inside WiceGrid, using your custom class
- use the class in the column definition
Create Conditions Generator
Inside lib/wice/columns
add a new file called conditions_generator_column_plan_request_identifier.rb
and add the following content:
module Wice
module Columns
class ConditionsGeneratorColumnPlanRequestIdentifier < ConditionsGeneratorColumn #:nodoc:
def generate_conditions(table_alias, opts) #:nodoc:
if opts.kind_of? String
string_fragment = opts
negation = ''
elsif (opts.kind_of? Hash) && opts.has_key?(:v)
string_fragment = opts[:v]
negation = opts[:n] == '1' ? 'NOT' : ''
else
Wice.log "invalid parameters for the grid string filter - must be a string: #{opts.inspect} or a Hash with keys :v and :n"
return false
end
if string_fragment.empty?
return false
end
table_name = @column_wrapper.alias_or_table_name(table_alias)
op = ::Wice.get_string_matching_operators(@column_wrapper.model)
search_value = "%#{string_fragment}%"
[
" #{negation} (#{table_name}.ident #{op} ? OR #{table_name}.external_id #{op} ?)",
search_value, search_value
]
end
end
end
end
This class is actually almost copied from the standard column generator, except I generate a different condition at the end, where I compare with two fields with an OR operator. This way I will find results if either the ident
or the external_id
matches the search-value.
Define filter type in config
In config/wice_grid_config.rb
add the following:
Wice::Defaults::ADDITIONAL_COLUMN_PROCESSORS = {
plan_request_identifier_filter: ['ViewColumnString', 'Wice::Columns::ConditionsGeneratorColumnPlanRequestIdentifier']
}
We just use the standard ViewColumnString
to just show us a string filter.
Use the filter_type in the column
To enable the filter in the column, we just have to write the following:
g.column name: 'Id', attribute: 'ident', filter_type: :plan_request_identifier_filter, in_csv: false do |pr|
render 'title_with_info', plan_request: pr
end