Skip to content

Commit

Permalink
Merge pull request #36 from brightin/ransack-filtering
Browse files Browse the repository at this point in the history
First shot at an automatic ransack implementation
  • Loading branch information
jvdp committed Apr 29, 2014
2 parents 909385c + ab789ef commit 8a981ef
Show file tree
Hide file tree
Showing 17 changed files with 137 additions and 19 deletions.
1 change: 1 addition & 0 deletions core/app/controllers/brightcontent/base_controller.rb
Expand Up @@ -9,6 +9,7 @@ class BaseController < ApplicationController
include BaseControllerExt::DefaultActions
include BaseControllerExt::Pagination
include BaseControllerExt::Fields
include BaseControllerExt::Filtering

def permitted_params
params.permit!
Expand Down
4 changes: 4 additions & 0 deletions core/app/helpers/brightcontent/base_helper.rb
Expand Up @@ -4,6 +4,10 @@ def render_list_field(item, field)
ViewLookup::ListField.new(self, item: item, field: field).call
end

def render_filter_field(form, field)
ViewLookup::FilterField.new(self, field: field, form: form).call
end

def render_form_field(form, field)
ViewLookup::FormField.new(self, item: form.object, field: field, form: form).call
end
Expand Down
12 changes: 12 additions & 0 deletions core/app/views/brightcontent/base/_list_filters.html.erb
@@ -0,0 +1,12 @@
<% if filter_fields.present? %>
<div class="panel-body">
<%= search_form_for ransack_search, class: "form-inline" do |form| %>
<% filter_fields.each do |field| %>
<div class="form-group">
<%= render_filter_field form, field %>
</div>
<% end %>
<%= form.submit class: "btn btn-default btn-sm" %>
<% end %>
</div>
<% end %>
6 changes: 6 additions & 0 deletions core/app/views/brightcontent/base/_list_header.html.erb
@@ -0,0 +1,6 @@
<div class="page-header">
<%= link_to "#{I18n.t('brightcontent.create_new', model: resource_class.model_name.human).capitalize}", polymorphic_url(resource_index_path, action: :new), class: "btn btn-primary pull-right" %>
<h1><%= nominative_plural(resource_class).capitalize %></h1>
</div>

<%= render_if_exists "index_top" %>
7 changes: 2 additions & 5 deletions core/app/views/brightcontent/base/index.html.erb
@@ -1,9 +1,6 @@
<div class="page-header">
<%= link_to "#{I18n.t('brightcontent.create_new', model: resource_class.model_name.human).capitalize}", polymorphic_url(resource_index_path, action: :new), class: "btn btn-primary pull-right" %>
<h1><%= nominative_plural(resource_class).capitalize %></h1>
</div>
<%= render "list_header" %>
<%= render_if_exists "index_top" %>
<%= render "list_filters" %>

<div class="table-responsive">
<table class="table table-hover">
Expand Down
1 change: 1 addition & 0 deletions core/brightcontent-core.gemspec
Expand Up @@ -26,6 +26,7 @@ Gem::Specification.new do |s|
s.add_dependency "simple_form"
s.add_dependency "will_paginate"
s.add_dependency "will_paginate-bootstrap"
s.add_dependency "ransack", "~> 1.1"

s.add_development_dependency "rake"
s.add_development_dependency "sqlite3"
Expand Down
1 change: 1 addition & 0 deletions core/lib/brightcontent/base_controller_ext.rb
Expand Up @@ -3,5 +3,6 @@ module BaseControllerExt
autoload :DefaultActions, 'brightcontent/base_controller_ext/default_actions'
autoload :Pagination, 'brightcontent/base_controller_ext/pagination'
autoload :Fields, 'brightcontent/base_controller_ext/fields'
autoload :Filtering, 'brightcontent/base_controller_ext/filtering'
end
end
16 changes: 7 additions & 9 deletions core/lib/brightcontent/base_controller_ext/fields.rb
Expand Up @@ -3,9 +3,9 @@ module BaseControllerExt
module Fields
extend ActiveSupport::Concern

module ClassMethods
def define_setting(name)
class_eval <<-RUBY
included do
%w[list_fields filter_fields form_fields default_fields].each do |name|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.#{name}(*fields)
define_method(:#{name}) { fields.flatten }
end
Expand All @@ -14,18 +14,16 @@ def self.#{name}(*fields)
end
end

included do
define_setting :list_fields
define_setting :form_fields
define_setting :default_fields
end

protected

def list_fields
default_fields
end

def filter_fields
[]
end

def form_fields
default_fields
end
Expand Down
21 changes: 21 additions & 0 deletions core/lib/brightcontent/base_controller_ext/filtering.rb
@@ -0,0 +1,21 @@
require 'active_support/concern'

module Brightcontent
module BaseControllerExt
module Filtering
extend ActiveSupport::Concern

included do
helper_method :ransack_search
end

def ransack_search
@_ransack_search ||= end_of_association_chain.ransack(params[:q])
end

def collection
@_collection ||= ransack_search.result(distinct: true)
end
end
end
end
1 change: 1 addition & 0 deletions core/lib/brightcontent/core.rb
Expand Up @@ -2,6 +2,7 @@
require "bootstrap-sass"
require "bootstrap-wysihtml5-rails"
require "inherited_resources"
require "ransack"
require "jquery-rails"
require "simple_form"
require "will_paginate"
Expand Down
1 change: 1 addition & 0 deletions core/lib/brightcontent/view_lookup.rb
Expand Up @@ -3,5 +3,6 @@ module ViewLookup
autoload :Abstract, 'brightcontent/view_lookup/abstract'
autoload :FormField, 'brightcontent/view_lookup/form_field'
autoload :ListField, 'brightcontent/view_lookup/list_field'
autoload :FilterField, 'brightcontent/view_lookup/filter_field'
end
end
4 changes: 2 additions & 2 deletions core/lib/brightcontent/view_lookup/abstract.rb
Expand Up @@ -30,15 +30,15 @@ def render_default
end

def field_type
NotImplementedError
raise NotImplementedError
end

def name
self.class.name.demodulize.underscore
end

def field_value
value = options[:item].send(options[:field])
options[:item].send(options[:field])
end

def render(*args)
Expand Down
57 changes: 57 additions & 0 deletions core/lib/brightcontent/view_lookup/filter_field.rb
@@ -0,0 +1,57 @@
module Brightcontent
module ViewLookup
class FilterField < Abstract
def render_default
raise "invalid filter field: #{options[:field]}" unless field_name
[
options[:form].label(:"#{field_name}_eq", options[:field].humanize),
options[:form].select(:"#{field_name}_eq", select_options, {include_blank: true}, class: "form-control input-sm")
].join(" ").html_safe
end

def field_type
resource_class.columns_hash[options[:field]].try :type
end

private

def field?
resource_class.column_names.include? options[:field].to_s
end

def belongs_to_association?
association.try :belongs_to?
end

def field_name
if field?
options[:field]
elsif belongs_to_assocation?
association.foreign_key
end
end

def select_options
if field?
field_type == :boolean ? raw_options : raw_options.sort
elsif belongs_to_assocation?
association.klass.where(association.association_primary_key => raw_options).map do |record|
[record, record[association.association_primary_key]]
end
end
end

def raw_options
resource_class.uniq.pluck(field_name)
end

def association
resource_class.reflect_on_association options[:field].to_sym
end

def resource_class
view_context.send :resource_class
end
end
end
end
@@ -1,2 +1,3 @@
class Brightcontent::BlogsController < Brightcontent::BaseController
filter_fields %w[featured]
end
4 changes: 4 additions & 0 deletions core/spec/factories.rb
Expand Up @@ -13,5 +13,9 @@
name "Blogname"
body "Inhoud"
featured false

factory :featured_blog do
featured true
end
end
end
17 changes: 15 additions & 2 deletions core/spec/features/resources_index_spec.rb
Expand Up @@ -22,7 +22,15 @@
given_10_per_page
given_31_blog_items
visit_blogs_page
page.should have_css("tbody tr", :count => 10)
page_should_have_n_rows 10
end

scenario "Filter by 'featured'" do
given_31_blog_items
visit_blogs_page
select "true", from: "Featured"
click_button "Search"
page_should_have_n_rows 6
end

def visit_blogs_page
Expand All @@ -38,8 +46,13 @@ def page_should_have_valid_table
end
end

def page_should_have_n_rows(n)
page.should have_css("tbody tr", :count => n)
end

def given_31_blog_items
31.times { create :blog }
25.times { create :blog }
6.times { create :featured_blog }
end

def given_10_per_page
Expand Down
2 changes: 1 addition & 1 deletion pages/app/views/brightcontent/pages/index.html.erb
Expand Up @@ -7,6 +7,6 @@

<div class="panel-body">
<ol class="sortable_tree" data-rebuild_url="<%=rebuild_pages_url%>" data-max_levels="5">
<%= sortable_tree @pages %>
<%= sortable_tree collection %>
</ol>
</div>

0 comments on commit 8a981ef

Please sign in to comment.