Skip to content

Commit 0f515a0

Browse files
ebeigartsgregbell
authored andcommitted
Refactored all the input helers to use the new Formtastic 2.0 custom inputs.
1 parent 575a879 commit 0f515a0

14 files changed

+287
-184
lines changed

activeadmin.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
2020
s.add_dependency("rails", ">= 3.0.0")
2121
s.add_dependency("meta_search", ">= 0.9.2")
2222
s.add_dependency("devise", ">= 1.1.2")
23-
s.add_dependency("formtastic", "< 2.0.0")
23+
s.add_dependency("formtastic", ">= 2.0.0")
2424
s.add_dependency("inherited_resources", "< 1.3.0")
2525
s.add_dependency("kaminari", ">= 0.12.4")
2626
s.add_dependency("sass", ">= 3.1.0")

lib/active_admin.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'meta_search'
22
require 'devise'
33
require 'kaminari'
4+
require 'formtastic'
45
require 'sass'
56
require 'active_admin/arbre'
67
require 'active_admin/engine'
@@ -22,6 +23,8 @@ module ActiveAdmin
2223
autoload :DSL, 'active_admin/dsl'
2324
autoload :Event, 'active_admin/event'
2425
autoload :FormBuilder, 'active_admin/form_builder'
26+
autoload :FilterFormBuilder, 'active_admin/filter_form_builder'
27+
autoload :Inputs, 'active_admin/inputs'
2528
autoload :Iconic, 'active_admin/iconic'
2629
autoload :Menu, 'active_admin/menu'
2730
autoload :MenuItem, 'active_admin/menu_item'
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module ActiveAdmin
2+
# This form builder defines methods to build filter forms such
3+
# as the one found in the sidebar of the index page of a standard resource.
4+
class FilterFormBuilder < FormBuilder
5+
6+
def filter(method, options = {})
7+
return "" if method.nil? || method == ""
8+
options[:as] ||= default_input_type(method)
9+
return "" unless options[:as]
10+
content = input(method, options)
11+
form_buffers.last << content.html_safe if content
12+
end
13+
14+
protected
15+
16+
# Returns the default filter type for a given attribute
17+
def default_input_type(method, options = {})
18+
if column = column_for(method)
19+
case column.type
20+
when :date, :datetime
21+
return :date_range
22+
when :string, :text
23+
return :string
24+
when :integer
25+
return :select if reflection_for(method.to_s.gsub('_id','').to_sym)
26+
return :numeric
27+
when :float, :decimal
28+
return :numeric
29+
end
30+
end
31+
32+
if reflection = reflection_for(method)
33+
return :select if reflection.macro == :belongs_to && !reflection.options[:polymorphic]
34+
end
35+
end
36+
37+
def custom_input_class_name(as)
38+
"ActiveAdmin::Inputs::Filter#{as.to_s.camelize}Input"
39+
end
40+
41+
# Returns the column for an attribute on the object being searched
42+
# if it exists. Otherwise returns nil
43+
def column_for(method)
44+
@object.base.columns_hash[method.to_s] if @object.base.respond_to?(:columns_hash)
45+
end
46+
47+
# Returns the association reflection for the method if it exists
48+
def reflection_for(method)
49+
@object.base.reflect_on_association(method) if @object.base.respond_to?(:reflect_on_association)
50+
end
51+
52+
end
53+
end

lib/active_admin/form_builder.rb

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
require 'formtastic'
2-
31
module ActiveAdmin
4-
class FormBuilder < ::Formtastic::SemanticFormBuilder
2+
class FormBuilder < ::Formtastic::FormBuilder
53

64
attr_reader :form_buffers
75

@@ -21,8 +19,6 @@ def inputs(*args, &block)
2119
# its contents, so we want to skip the internal buffering
2220
# while building up its contents
2321
def input(method, *args)
24-
return if polymorphic_belongs_to_association?(method)
25-
2622
content = with_new_form_buffer { super }
2723
return content.html_safe unless @inputs_with_block
2824
form_buffers.last << content.html_safe
@@ -52,14 +48,6 @@ def commit_button_with_cancel_link
5248
content << cancel_link
5349
end
5450

55-
def datepicker_input(method, options)
56-
options = options.dup
57-
options[:input_html] ||= {}
58-
options[:input_html][:class] = [options[:input_html][:class], "datepicker"].compact.join(' ')
59-
options[:input_html][:size] ||= "10"
60-
string_input(method, options)
61-
end
62-
6351
def has_many(association, options = {}, &block)
6452
options = { :for => association }.merge(options)
6553
options[:class] ||= ""
@@ -98,15 +86,14 @@ def has_many(association, options = {}, &block)
9886
form_buffers.last << content.html_safe
9987
end
10088

101-
private
89+
protected
10290

103-
# Pass in a method to check if it's a polymorphic association
104-
def polymorphic_belongs_to_association?(method)
105-
reflection = reflection_for(method)
106-
107-
reflection && reflection.macro == :belongs_to && reflection.options[:polymorphic]
91+
def custom_input_class_name(as)
92+
"ActiveAdmin::Inputs::#{as.to_s.camelize}Input"
10893
end
10994

95+
private
96+
11097
def with_new_form_buffer
11198
form_buffers << "".html_safe
11299
return_value = yield

lib/active_admin/inputs.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module ActiveAdmin
2+
module Inputs
3+
extend ActiveSupport::Autoload
4+
5+
autoload :DatepickerInput
6+
7+
autoload :FilterBase
8+
autoload :FilterStringInput
9+
autoload :FilterDateRangeInput
10+
autoload :FilterNumericInput
11+
autoload :FilterSelectInput
12+
autoload :FilterCheckBoxesInput
13+
end
14+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module ActiveAdmin
2+
module Inputs
3+
class DatepickerInput < ::Formtastic::Inputs::StringInput
4+
def input_html_options
5+
options = super
6+
options[:class] = [options[:class], "datepicker"].compact.join(' ')
7+
options
8+
end
9+
end
10+
end
11+
end
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module ActiveAdmin
2+
module Inputs
3+
module FilterBase
4+
include ::Formtastic::Inputs::Base
5+
6+
def input_wrapping(&block)
7+
template.content_tag(:div,
8+
template.capture(&block),
9+
wrapper_html_options
10+
)
11+
end
12+
13+
def required?
14+
false
15+
end
16+
17+
def wrapper_html_options
18+
{ :class => "filter_form_field #{as}" }
19+
end
20+
21+
# Override the standard finder to accept a proc
22+
def collection_from_options
23+
if options[:collection].is_a?(Proc)
24+
options[:collection].call
25+
else
26+
super
27+
end
28+
end
29+
30+
# Returns the default label for a given attribute
31+
# Will use ActiveModel I18n if possible
32+
def default_filter_label(method)
33+
if @object.base.respond_to?(:human_attribute_name)
34+
@object.base.human_attribute_name(method)
35+
else
36+
method.to_s.titlecase
37+
end
38+
end
39+
40+
# Returns the association reflection for the method if it exists
41+
def reflection_for(method)
42+
@object.base.reflect_on_association(method) if @object.base.respond_to?(:reflect_on_association)
43+
end
44+
end
45+
end
46+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module ActiveAdmin
2+
module Inputs
3+
class FilterCheckBoxesInput < ::Formtastic::Inputs::CheckBoxesInput
4+
include FilterBase
5+
6+
def input_name
7+
"#{object_name}[#{association_primary_key || method}_in][]"
8+
end
9+
end
10+
end
11+
end
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
module ActiveAdmin
2+
module Inputs
3+
class FilterDateRangeInput < ::Formtastic::Inputs::StringInput
4+
include FilterBase
5+
6+
def to_html
7+
input_wrapping do
8+
[ label_html,
9+
builder.text_field(gt_input_name, input_html_options(gt_input_name)),
10+
template.content_tag(:span, "-", :class => "seperator"),
11+
builder.text_field(lt_input_name, input_html_options(lt_input_name)),
12+
].join("\n").html_safe
13+
end
14+
end
15+
16+
def gt_input_name
17+
"#{method}_gte"
18+
end
19+
alias :input_name :gt_input_name
20+
21+
def lt_input_name
22+
"#{method}_lte"
23+
end
24+
25+
def input_html_options(input_name = gt_input_name)
26+
current_value = @object.send(input_name)
27+
{ :size => 12,
28+
:class => "datepicker",
29+
:max => 10,
30+
:value => current_value.respond_to?(:strftime) ? current_value.strftime("%Y-%m-%d") : "" }
31+
end
32+
end
33+
end
34+
end
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module ActiveAdmin
2+
module Inputs
3+
class FilterNumericInput < ::Formtastic::Inputs::NumberInput
4+
include FilterBase
5+
6+
def to_html
7+
input_wrapping do
8+
[ label_html,
9+
select_html,
10+
" ",
11+
input_html
12+
].join("\n").html_safe
13+
end
14+
end
15+
16+
def input_html
17+
builder.text_field current_filter, input_html_options
18+
end
19+
20+
def input_html_options
21+
{ :size => 10, :id => "#{method}_numeric" }
22+
end
23+
24+
def select_html
25+
template.select_tag '', select_options, select_html_options
26+
end
27+
28+
def select_options
29+
template.options_for_select(filters, current_filter)
30+
end
31+
32+
def select_html_options
33+
{ :onchange => "document.getElementById('#{method}_numeric').name = 'q[' + this.value + ']';" }
34+
end
35+
36+
# Returns the scope for which we are currently searching. If no search is available
37+
# it returns the first scope
38+
def current_filter
39+
filters[1..-1].inject(filters.first){|a,b| @object.send(b[1].to_sym) ? b : a }[1]
40+
end
41+
42+
def filters
43+
(options[:filters] || default_filters).collect do |scope|
44+
[scope[0], [method, scope[1]].join("_")]
45+
end
46+
end
47+
48+
def default_filters
49+
[ [I18n.t('active_admin.equal_to'), 'eq'],
50+
[I18n.t('active_admin.greater_than'), 'gt'],
51+
[I18n.t('active_admin.less_than'), 'lt'] ]
52+
end
53+
end
54+
end
55+
end

0 commit comments

Comments
 (0)