facet_for 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/facet_for.gemspec +24 -0
- data/lib/facet_for/version.rb +3 -0
- data/lib/facet_for.rb +176 -0
- metadata +62 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/facet_for.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "facet_for/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "facet_for"
|
7
|
+
s.version = FacetFor::VERSION
|
8
|
+
s.authors = ["Jonathan Barket"]
|
9
|
+
s.email = ["jbarket@sleepunit.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Provides helpers for creating search forms with Ransack}
|
12
|
+
s.description = %q{Provides helpers for creating search forms with Ransack}
|
13
|
+
|
14
|
+
s.rubyforge_project = "facet_for"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
s.add_runtime_dependency "ransack"
|
24
|
+
end
|
data/lib/facet_for.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
require "facet_for/version"
|
2
|
+
|
3
|
+
class ActionView::Helpers::FormBuilder
|
4
|
+
include ActionView::Helpers::TagHelper
|
5
|
+
include ActionView::Helpers::FormTagHelper
|
6
|
+
include ActionView::Helpers::FormOptionsHelper
|
7
|
+
include ActionView::Helpers::CaptureHelper
|
8
|
+
include ActionView::Helpers::AssetTagHelper
|
9
|
+
|
10
|
+
def facet_for(column, *args)
|
11
|
+
options = args.extract_options!
|
12
|
+
|
13
|
+
facet_html = ''
|
14
|
+
|
15
|
+
# Here, we collect information about the facet. What the user doesn't
|
16
|
+
# supply, we'll make our best guess for.
|
17
|
+
|
18
|
+
facet = { }
|
19
|
+
facet[:model] = @object.klass
|
20
|
+
|
21
|
+
facet[:column] = facet[:model].content_columns.select { |x| x.name == column.to_s }
|
22
|
+
|
23
|
+
# Information about the column. This is used to generate the default
|
24
|
+
# label, and to pass the right selector to the Ransack fields.
|
25
|
+
|
26
|
+
facet[:column_name] = options[:column_name]
|
27
|
+
facet[:column_type] = options[:column_type]
|
28
|
+
|
29
|
+
# This is the type of field we will render. If this isn't provided, we'll
|
30
|
+
# determine this based on facet_column_type
|
31
|
+
|
32
|
+
facet[:type] = options[:type]
|
33
|
+
|
34
|
+
# In the specific case of facet_type == :collection, we'll allow the user
|
35
|
+
# to specify their own collection. If it's an association, we'll attempt
|
36
|
+
# to provide one.
|
37
|
+
|
38
|
+
facet[:collection] = options[:collection]
|
39
|
+
|
40
|
+
if facet[:column].empty? # facet doesn't exist
|
41
|
+
|
42
|
+
# Is it an association?
|
43
|
+
#
|
44
|
+
# We check for :singular_name, :plural_name and :singular_id
|
45
|
+
|
46
|
+
if association = associations_for(facet[:model]).select { |x|
|
47
|
+
x.plural_name == column.to_s or
|
48
|
+
x.plural_name.singularize == column.to_s or
|
49
|
+
x.primary_key_name == column.to_s }.uniq
|
50
|
+
|
51
|
+
if association.first.macro == :has_many
|
52
|
+
|
53
|
+
# For a has_many relationship, we want the plural name with _id.
|
54
|
+
# Ransack will then look at the _id column for the associated model.
|
55
|
+
# This won't work properly on models with nonstandard id column
|
56
|
+
# names. That's a problem, but whatevs for the time being.
|
57
|
+
|
58
|
+
facet[:column_name] = "#{association.first.plural_name}_id"
|
59
|
+
|
60
|
+
elsif association.first.macro == :belongs_to
|
61
|
+
|
62
|
+
# If we're dealing with belongs_to, we can assume we just want
|
63
|
+
# to look at the foreign key on the current model. Much simpler.
|
64
|
+
|
65
|
+
facet[:column_name] = association.first.foreign_key
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
# By default, we want to use a select box with a collection of
|
70
|
+
# what this model has_many of. If the user has specified something,
|
71
|
+
# we'll run with what they specified.
|
72
|
+
|
73
|
+
facet[:type] = facet[:type] || :collection
|
74
|
+
|
75
|
+
# If the user hasn't specified a collection, we'll provide one now
|
76
|
+
# based on this association
|
77
|
+
|
78
|
+
facet[:collection] = facet[:collection] || association.first.klass.all
|
79
|
+
|
80
|
+
else
|
81
|
+
return # nothing found
|
82
|
+
end
|
83
|
+
else
|
84
|
+
|
85
|
+
# We found a column. Let's yank some useful information out of it
|
86
|
+
|
87
|
+
facet[:column] = facet[:column].first
|
88
|
+
facet[:column_name] = facet[:column].name
|
89
|
+
facet[:column_type] = facet[:column_type] || facet[:column].type
|
90
|
+
end
|
91
|
+
|
92
|
+
facet[:type] = facet[:type] || default_facet_type(facet)
|
93
|
+
|
94
|
+
|
95
|
+
# Insert our label first
|
96
|
+
|
97
|
+
facet_html = "<div class=\"label #{additional_classes(facet)}\">"
|
98
|
+
|
99
|
+
if options[:label]
|
100
|
+
facet_html << self.label(column, options[:label])
|
101
|
+
else
|
102
|
+
facet_html << default_label_for_facet(facet)
|
103
|
+
end
|
104
|
+
|
105
|
+
facet_html << "</div>"
|
106
|
+
|
107
|
+
# And now the fields
|
108
|
+
|
109
|
+
facet_html << render_facet_for(facet)
|
110
|
+
|
111
|
+
facet_html.html_safe
|
112
|
+
end
|
113
|
+
|
114
|
+
# If the user doesn't pass options[:label], we'll build a default label
|
115
|
+
# based on the type of facet we're rendering.
|
116
|
+
|
117
|
+
def default_label_for_facet(facet)
|
118
|
+
case facet[:type]
|
119
|
+
when :cont
|
120
|
+
return self.label("#{facet[:column_name]}_cont".to_sym)
|
121
|
+
else
|
122
|
+
return self.label("#{facet[:column_name]}")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Now that we have our type, we can render the actual form field for
|
127
|
+
# Ransack
|
128
|
+
|
129
|
+
def render_facet_for(facet)
|
130
|
+
|
131
|
+
facet_html = "<div class=\"input #{additional_classes(facet)}\">"
|
132
|
+
|
133
|
+
case facet[:type]
|
134
|
+
when :cont
|
135
|
+
facet_html << self.text_field("#{facet[:column_name]}_cont".to_sym)
|
136
|
+
when :collection
|
137
|
+
facet_html << self.collection_select("#{facet[:column_name]}_eq".to_sym, facet[:collection], :id, :to_s, :include_blank => true)
|
138
|
+
when :between
|
139
|
+
facet_html << "From "
|
140
|
+
facet_html << self.text_field("#{facet[:column_name]}_gteq".to_sym, :size => 11)
|
141
|
+
facet_html << "To "
|
142
|
+
facet_html << self.text_field("#{facet[:column_name]}_lteq".to_sym, :size => 11)
|
143
|
+
when :gteq
|
144
|
+
facet_html << self.text_field("#{facet[:column_name]}_gteq".to_sym, :size => 5)
|
145
|
+
when :lteq
|
146
|
+
facet_html << self.text_field("#{facet[:column_name]}_gteq".to_sym, :size => 5)
|
147
|
+
end
|
148
|
+
|
149
|
+
facet_html << "</div>"
|
150
|
+
facet_html
|
151
|
+
end
|
152
|
+
|
153
|
+
# If no options[:type] is specified, we'll look at the column type for
|
154
|
+
# the column in the model and make an educated guess.
|
155
|
+
|
156
|
+
def default_facet_type(facet)
|
157
|
+
|
158
|
+
case facet[:column_type]
|
159
|
+
when :string, :text
|
160
|
+
return :cont
|
161
|
+
when :datetime, :date, :float, :integer, :double
|
162
|
+
return :between
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def additional_classes(facet)
|
167
|
+
additional_class = "#{facet[:type]} #{facet[:column_type]}"
|
168
|
+
end
|
169
|
+
|
170
|
+
# We can use reflections to determine has_many and belongs_to associations
|
171
|
+
|
172
|
+
def associations_for(model)
|
173
|
+
model.reflections.values
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: facet_for
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jonathan Barket
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-19 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ransack
|
16
|
+
requirement: &84397210 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *84397210
|
25
|
+
description: Provides helpers for creating search forms with Ransack
|
26
|
+
email:
|
27
|
+
- jbarket@sleepunit.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- Rakefile
|
35
|
+
- facet_for.gemspec
|
36
|
+
- lib/facet_for.rb
|
37
|
+
- lib/facet_for/version.rb
|
38
|
+
homepage: ''
|
39
|
+
licenses: []
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project: facet_for
|
58
|
+
rubygems_version: 1.8.10
|
59
|
+
signing_key:
|
60
|
+
specification_version: 3
|
61
|
+
summary: Provides helpers for creating search forms with Ransack
|
62
|
+
test_files: []
|