administrate 0.8.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of administrate might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/app/assets/javascripts/administrate/components/date_time_picker.js +5 -1
- data/app/assets/stylesheets/administrate/base/_typography.scss +1 -1
- data/app/assets/stylesheets/administrate/components/_cells.scss +2 -6
- data/app/assets/stylesheets/docs.scss +1 -0
- data/app/controllers/administrate/application_controller.rb +53 -13
- data/app/controllers/concerns/administrate/punditize.rb +36 -0
- data/app/helpers/administrate/application_helper.rb +26 -7
- data/app/views/administrate/application/_collection.html.erb +11 -10
- data/app/views/administrate/application/_flashes.html.erb +1 -1
- data/app/views/administrate/application/_form.html.erb +5 -2
- data/app/views/administrate/application/{_icons.erb → _icons.html.erb} +0 -0
- data/app/views/administrate/application/_navigation.html.erb +1 -1
- data/app/views/administrate/application/edit.html.erb +3 -3
- data/app/views/administrate/application/index.html.erb +7 -2
- data/app/views/administrate/application/new.html.erb +6 -1
- data/app/views/administrate/application/show.html.erb +4 -4
- data/app/views/fields/belongs_to/_index.html.erb +1 -1
- data/app/views/fields/belongs_to/_show.html.erb +1 -1
- data/app/views/fields/date_time/_form.html.erb +1 -1
- data/app/views/fields/date_time/_index.html.erb +1 -1
- data/app/views/fields/has_many/_form.html.erb +2 -2
- data/app/views/fields/has_many/_index.html.erb +1 -1
- data/app/views/fields/has_many/_show.html.erb +8 -5
- data/app/views/fields/has_one/_form.html.erb +1 -1
- data/app/views/fields/password/_form.html.erb +23 -0
- data/app/views/fields/password/_index.html.erb +18 -0
- data/app/views/fields/password/_show.html.erb +18 -0
- data/app/views/fields/polymorphic/_form.html.erb +11 -9
- data/app/views/fields/polymorphic/_show.html.erb +8 -4
- data/app/views/fields/select/_form.html.erb +1 -1
- data/app/views/fields/time/_form.html.erb +22 -0
- data/app/views/fields/time/_index.html.erb +17 -0
- data/app/views/fields/time/_show.html.erb +17 -0
- data/app/views/fields/url/_form.html.erb +23 -0
- data/app/views/fields/url/_index.html.erb +20 -0
- data/app/views/fields/url/_show.html.erb +20 -0
- data/app/views/layouts/administrate/application.html.erb +1 -1
- data/config/locales/administrate.al.yml +28 -0
- data/config/locales/administrate.ar.yml +6 -6
- data/config/locales/administrate.bs.yml +27 -0
- data/config/locales/administrate.ca.yml +28 -0
- data/config/locales/administrate.da.yml +6 -6
- data/config/locales/administrate.de.yml +8 -8
- data/config/locales/administrate.en.yml +6 -6
- data/config/locales/administrate.es.yml +6 -6
- data/config/locales/administrate.fr.yml +6 -6
- data/config/locales/administrate.id.yml +28 -0
- data/config/locales/administrate.it.yml +6 -6
- data/config/locales/administrate.ja.yml +6 -6
- data/config/locales/administrate.ko.yml +11 -11
- data/config/locales/administrate.nl.yml +6 -6
- data/config/locales/administrate.pl.yml +6 -6
- data/config/locales/administrate.pt-BR.yml +6 -6
- data/config/locales/administrate.pt.yml +6 -6
- data/config/locales/administrate.ru.yml +6 -6
- data/config/locales/administrate.sv.yml +6 -6
- data/config/locales/administrate.uk.yml +6 -6
- data/config/locales/administrate.vi.yml +6 -6
- data/config/locales/administrate.zh-CN.yml +6 -6
- data/config/locales/administrate.zh-TW.yml +8 -8
- data/docs/authorization.md +69 -0
- data/docs/customizing_attribute_partials.md +20 -1
- data/docs/customizing_controller_actions.md +2 -1
- data/docs/customizing_dashboards.md +152 -4
- data/docs/customizing_page_views.md +5 -1
- data/docs/getting_started.md +60 -10
- data/docs/rails_api.md +43 -0
- data/lib/administrate/base_dashboard.rb +27 -8
- data/lib/administrate/engine.rb +1 -1
- data/lib/administrate/field/associative.rb +8 -4
- data/lib/administrate/field/base.rb +1 -1
- data/lib/administrate/field/belongs_to.rb +6 -3
- data/lib/administrate/field/date_time.rb +13 -2
- data/lib/administrate/field/deferred.rb +10 -5
- data/lib/administrate/field/has_many.rb +18 -11
- data/lib/administrate/field/has_one.rb +16 -8
- data/lib/administrate/field/password.rb +25 -0
- data/lib/administrate/field/polymorphic.rb +41 -3
- data/lib/administrate/field/time.rb +8 -0
- data/lib/administrate/field/url.rb +21 -0
- data/lib/administrate/namespace.rb +1 -1
- data/lib/administrate/order.rb +40 -5
- data/lib/administrate/page/base.rb +8 -0
- data/lib/administrate/page/collection.rb +5 -1
- data/lib/administrate/resource_resolver.rb +2 -2
- data/lib/administrate/search.rb +121 -10
- data/lib/administrate/version.rb +1 -1
- data/lib/generators/administrate/dashboard/USAGE +1 -1
- data/lib/generators/administrate/dashboard/dashboard_generator.rb +11 -3
- data/lib/generators/administrate/dashboard/templates/controller.rb.erb +24 -11
- data/lib/generators/administrate/dashboard/templates/dashboard.rb.erb +18 -6
- data/lib/generators/administrate/install/install_generator.rb +13 -6
- data/lib/generators/administrate/install/templates/{application_controller.rb → application_controller.rb.erb} +1 -1
- data/lib/generators/administrate/routes/routes_generator.rb +11 -1
- data/lib/generators/administrate/routes/templates/routes.rb.erb +1 -1
- data/lib/generators/administrate/views/field_generator.rb +19 -5
- data/lib/generators/administrate/views/layout_generator.rb +1 -0
- metadata +41 -28
- data/config/secrets.yml +0 -14
@@ -9,6 +9,9 @@ require "administrate/field/polymorphic"
|
|
9
9
|
require "administrate/field/select"
|
10
10
|
require "administrate/field/string"
|
11
11
|
require "administrate/field/text"
|
12
|
+
require "administrate/field/time"
|
13
|
+
require "administrate/field/url"
|
14
|
+
require "administrate/field/password"
|
12
15
|
|
13
16
|
module Administrate
|
14
17
|
class BaseDashboard
|
@@ -30,6 +33,10 @@ module Administrate
|
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
36
|
+
def all_attributes
|
37
|
+
attribute_types.keys
|
38
|
+
end
|
39
|
+
|
33
40
|
def form_attributes
|
34
41
|
self.class::FORM_ATTRIBUTES
|
35
42
|
end
|
@@ -52,15 +59,12 @@ module Administrate
|
|
52
59
|
"#{resource.class} ##{resource.id}"
|
53
60
|
end
|
54
61
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
collection_attributes.map do |key|
|
59
|
-
field = self.class::ATTRIBUTE_TYPES[key]
|
62
|
+
def collection_includes
|
63
|
+
attribute_includes(collection_attributes)
|
64
|
+
end
|
60
65
|
|
61
|
-
|
62
|
-
|
63
|
-
end.compact
|
66
|
+
def item_includes
|
67
|
+
attribute_includes(show_page_attributes)
|
64
68
|
end
|
65
69
|
|
66
70
|
private
|
@@ -68,5 +72,20 @@ module Administrate
|
|
68
72
|
def attribute_not_found_message(attr)
|
69
73
|
"Attribute #{attr} could not be found in #{self.class}::ATTRIBUTE_TYPES"
|
70
74
|
end
|
75
|
+
|
76
|
+
def association_classes
|
77
|
+
@association_classes ||=
|
78
|
+
ObjectSpace.each_object(Class).
|
79
|
+
select { |klass| klass < Administrate::Field::Associative }
|
80
|
+
end
|
81
|
+
|
82
|
+
def attribute_includes(attributes)
|
83
|
+
attributes.map do |key|
|
84
|
+
field = self.class::ATTRIBUTE_TYPES[key]
|
85
|
+
|
86
|
+
next key if association_classes.include?(field)
|
87
|
+
key if association_classes.include?(field.try(:deferred_class))
|
88
|
+
end.compact
|
89
|
+
end
|
71
90
|
end
|
72
91
|
end
|
data/lib/administrate/engine.rb
CHANGED
@@ -7,16 +7,16 @@ module Administrate
|
|
7
7
|
associated_dashboard.display_resource(data)
|
8
8
|
end
|
9
9
|
|
10
|
+
def associated_class
|
11
|
+
associated_class_name.constantize
|
12
|
+
end
|
13
|
+
|
10
14
|
protected
|
11
15
|
|
12
16
|
def associated_dashboard
|
13
17
|
"#{associated_class_name}Dashboard".constantize.new
|
14
18
|
end
|
15
19
|
|
16
|
-
def associated_class
|
17
|
-
associated_class_name.constantize
|
18
|
-
end
|
19
|
-
|
20
20
|
def associated_class_name
|
21
21
|
options.fetch(:class_name, attribute.to_s.singularize.camelcase)
|
22
22
|
end
|
@@ -24,6 +24,10 @@ module Administrate
|
|
24
24
|
def primary_key
|
25
25
|
options.fetch(:primary_key, :id)
|
26
26
|
end
|
27
|
+
|
28
|
+
def foreign_key
|
29
|
+
options.fetch(:foreign_key, :"#{attribute}_id")
|
30
|
+
end
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
@@ -3,12 +3,12 @@ require_relative "associative"
|
|
3
3
|
module Administrate
|
4
4
|
module Field
|
5
5
|
class BelongsTo < Associative
|
6
|
-
def self.permitted_attribute(attr)
|
6
|
+
def self.permitted_attribute(attr, _options = nil)
|
7
7
|
:"#{attr}_id"
|
8
8
|
end
|
9
9
|
|
10
10
|
def permitted_attribute
|
11
|
-
|
11
|
+
foreign_key
|
12
12
|
end
|
13
13
|
|
14
14
|
def associated_resource_options
|
@@ -24,7 +24,10 @@ module Administrate
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def candidate_resources
|
27
|
-
associated_class.all
|
27
|
+
scope = options[:scope] ? options[:scope].call : associated_class.all
|
28
|
+
|
29
|
+
order = options.delete(:order)
|
30
|
+
order ? scope.reorder(order) : scope
|
28
31
|
end
|
29
32
|
|
30
33
|
def display_candidate_resource(resource)
|
@@ -4,11 +4,18 @@ module Administrate
|
|
4
4
|
module Field
|
5
5
|
class DateTime < Base
|
6
6
|
def date
|
7
|
-
I18n.localize(
|
7
|
+
I18n.localize(
|
8
|
+
data.in_time_zone(timezone).to_date,
|
9
|
+
format: format,
|
10
|
+
)
|
8
11
|
end
|
9
12
|
|
10
13
|
def datetime
|
11
|
-
I18n.localize(
|
14
|
+
I18n.localize(
|
15
|
+
data.in_time_zone(timezone),
|
16
|
+
format: format,
|
17
|
+
default: data,
|
18
|
+
)
|
12
19
|
end
|
13
20
|
|
14
21
|
private
|
@@ -16,6 +23,10 @@ module Administrate
|
|
16
23
|
def format
|
17
24
|
options.fetch(:format, :default)
|
18
25
|
end
|
26
|
+
|
27
|
+
def timezone
|
28
|
+
options.fetch(:timezone, ::Time.zone.name || "UTC")
|
29
|
+
end
|
19
30
|
end
|
20
31
|
end
|
21
32
|
end
|
@@ -25,11 +25,16 @@ module Administrate
|
|
25
25
|
options.fetch(:searchable, deferred_class.searchable?)
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
:
|
30
|
-
|
31
|
-
|
32
|
-
)
|
28
|
+
def searchable_field
|
29
|
+
options.fetch(:searchable_field)
|
30
|
+
end
|
31
|
+
|
32
|
+
def permitted_attribute(attr, _options = nil)
|
33
|
+
options.fetch(:foreign_key,
|
34
|
+
deferred_class.permitted_attribute(attr, options))
|
35
|
+
end
|
36
|
+
|
37
|
+
delegate :html_class, to: :deferred_class
|
33
38
|
end
|
34
39
|
end
|
35
40
|
end
|
@@ -7,12 +7,12 @@ module Administrate
|
|
7
7
|
class HasMany < Associative
|
8
8
|
DEFAULT_LIMIT = 5
|
9
9
|
|
10
|
-
def self.permitted_attribute(
|
11
|
-
{ "#{
|
10
|
+
def self.permitted_attribute(attr, _options = nil)
|
11
|
+
{ "#{attr.to_s.singularize}_ids".to_sym => [] }
|
12
12
|
end
|
13
13
|
|
14
|
-
def associated_collection
|
15
|
-
Administrate::Page::Collection.new(associated_dashboard)
|
14
|
+
def associated_collection(order = self.order)
|
15
|
+
Administrate::Page::Collection.new(associated_dashboard, order: order)
|
16
16
|
end
|
17
17
|
|
18
18
|
def attribute_key
|
@@ -39,7 +39,7 @@ module Administrate
|
|
39
39
|
self.class.permitted_attribute(attribute)
|
40
40
|
end
|
41
41
|
|
42
|
-
def resources(page = 1)
|
42
|
+
def resources(page = 1, order = self.order)
|
43
43
|
resources = order.apply(data).page(page).per(limit)
|
44
44
|
includes.any? ? resources.includes(*includes) : resources
|
45
45
|
end
|
@@ -49,13 +49,24 @@ module Administrate
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def data
|
52
|
-
@data ||= associated_class.none
|
52
|
+
@data ||= associated_class.none
|
53
|
+
end
|
54
|
+
|
55
|
+
def order_from_params(params)
|
56
|
+
Administrate::Order.new(
|
57
|
+
params.fetch(:order, sort_by),
|
58
|
+
params.fetch(:direction, direction),
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def order
|
63
|
+
@order ||= Administrate::Order.new(sort_by, direction)
|
53
64
|
end
|
54
65
|
|
55
66
|
private
|
56
67
|
|
57
68
|
def includes
|
58
|
-
associated_dashboard.
|
69
|
+
associated_dashboard.collection_includes
|
59
70
|
end
|
60
71
|
|
61
72
|
def candidate_resources
|
@@ -71,10 +82,6 @@ module Administrate
|
|
71
82
|
associated_dashboard.display_resource(resource)
|
72
83
|
end
|
73
84
|
|
74
|
-
def order
|
75
|
-
@_order ||= Administrate::Order.new(sort_by, direction)
|
76
|
-
end
|
77
|
-
|
78
85
|
def sort_by
|
79
86
|
options[:sort_by]
|
80
87
|
end
|
@@ -3,25 +3,33 @@ require_relative "associative"
|
|
3
3
|
module Administrate
|
4
4
|
module Field
|
5
5
|
class HasOne < Associative
|
6
|
-
def
|
7
|
-
|
8
|
-
@nested_form = Administrate::Page::Form.new(
|
6
|
+
def nested_form
|
7
|
+
@nested_form ||= Administrate::Page::Form.new(
|
9
8
|
resolver.dashboard_class.new,
|
10
9
|
data || resolver.resource_class.new,
|
11
10
|
)
|
12
|
-
|
13
|
-
super
|
14
11
|
end
|
15
12
|
|
16
|
-
def self.permitted_attribute(attr)
|
13
|
+
def self.permitted_attribute(attr, options = nil)
|
14
|
+
associated_class_name =
|
15
|
+
if options
|
16
|
+
options.fetch(:class_name, attr.to_s.singularize.camelcase)
|
17
|
+
else
|
18
|
+
attr
|
19
|
+
end
|
17
20
|
related_dashboard_attributes =
|
18
|
-
Administrate::ResourceResolver.new("admin/#{
|
21
|
+
Administrate::ResourceResolver.new("admin/#{associated_class_name}").
|
19
22
|
dashboard_class.new.permitted_attributes + [:id]
|
20
23
|
|
21
24
|
{ "#{attr}_attributes": related_dashboard_attributes }
|
22
25
|
end
|
23
26
|
|
24
|
-
|
27
|
+
private
|
28
|
+
|
29
|
+
def resolver
|
30
|
+
@resolver ||=
|
31
|
+
Administrate::ResourceResolver.new("admin/#{associated_class_name}")
|
32
|
+
end
|
25
33
|
end
|
26
34
|
end
|
27
35
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
module Administrate
|
4
|
+
module Field
|
5
|
+
class Password < Field::Base
|
6
|
+
def self.searchable?
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
def truncate
|
11
|
+
data.to_s.gsub(/./, character)[0...truncation_length]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def truncation_length
|
17
|
+
options.fetch(:truncate, 50)
|
18
|
+
end
|
19
|
+
|
20
|
+
def character
|
21
|
+
options.fetch(:character, "•")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -2,11 +2,49 @@ require_relative "associative"
|
|
2
2
|
|
3
3
|
module Administrate
|
4
4
|
module Field
|
5
|
-
class Polymorphic <
|
5
|
+
class Polymorphic < BelongsTo
|
6
|
+
def associated_resource_grouped_options
|
7
|
+
classes.map do |klass|
|
8
|
+
[klass.to_s, candidate_resources_for(klass).map do |resource|
|
9
|
+
[display_candidate_resource(resource), resource.to_global_id]
|
10
|
+
end]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.permitted_attribute(attr, _options = nil)
|
15
|
+
{ attr => %i{type value} }
|
16
|
+
end
|
17
|
+
|
18
|
+
def permitted_attribute
|
19
|
+
{ attribute => %i{type value} }
|
20
|
+
end
|
21
|
+
|
22
|
+
def selected_global_id
|
23
|
+
data ? data.to_global_id : nil
|
24
|
+
end
|
25
|
+
|
6
26
|
protected
|
7
27
|
|
8
|
-
def associated_dashboard
|
9
|
-
"#{
|
28
|
+
def associated_dashboard(klass = data.class)
|
29
|
+
"#{klass.name}Dashboard".constantize.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def classes
|
33
|
+
options.fetch(:classes, [])
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def order
|
39
|
+
@_order ||= options.delete(:order)
|
40
|
+
end
|
41
|
+
|
42
|
+
def candidate_resources_for(klass)
|
43
|
+
order ? klass.order(order) : klass.all
|
44
|
+
end
|
45
|
+
|
46
|
+
def display_candidate_resource(resource)
|
47
|
+
associated_dashboard(resource.class).display_resource(resource)
|
10
48
|
end
|
11
49
|
end
|
12
50
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
module Administrate
|
4
|
+
module Field
|
5
|
+
class Url < Field::Base
|
6
|
+
def self.searchable?
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def truncate
|
11
|
+
data.to_s[0...truncation_length]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def truncation_length
|
17
|
+
options.fetch(:truncate, 50)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -12,7 +12,7 @@ module Administrate
|
|
12
12
|
|
13
13
|
def routes
|
14
14
|
@routes ||= all_routes.select do |controller, _action|
|
15
|
-
controller.starts_with?(namespace
|
15
|
+
controller.starts_with?("#{namespace}/")
|
16
16
|
end.map do |controller, action|
|
17
17
|
[controller.gsub(/^#{namespace}\//, ""), action]
|
18
18
|
end
|
data/lib/administrate/order.rb
CHANGED
@@ -6,11 +6,15 @@ module Administrate
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def apply(relation)
|
9
|
-
|
10
|
-
relation.
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
return order_by_association(relation) unless
|
10
|
+
reflect_association(relation).nil?
|
11
|
+
|
12
|
+
order = "#{relation.table_name}.#{attribute} #{direction}"
|
13
|
+
|
14
|
+
return relation.reorder(order) if
|
15
|
+
relation.columns_hash.keys.include?(attribute.to_s)
|
16
|
+
|
17
|
+
relation
|
14
18
|
end
|
15
19
|
|
16
20
|
def ordered_by?(attr)
|
@@ -41,5 +45,36 @@ module Administrate
|
|
41
45
|
def opposite_direction
|
42
46
|
direction.to_sym == :asc ? :desc : :asc
|
43
47
|
end
|
48
|
+
|
49
|
+
def order_by_association(relation)
|
50
|
+
return order_by_count(relation) if has_many_attribute?(relation)
|
51
|
+
|
52
|
+
return order_by_id(relation) if belongs_to_attribute?(relation)
|
53
|
+
|
54
|
+
relation
|
55
|
+
end
|
56
|
+
|
57
|
+
def order_by_count(relation)
|
58
|
+
relation.
|
59
|
+
left_joins(attribute.to_sym).
|
60
|
+
group(:id).
|
61
|
+
reorder("COUNT(#{attribute}.id) #{direction}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def order_by_id(relation)
|
65
|
+
relation.reorder("#{attribute}_id #{direction}")
|
66
|
+
end
|
67
|
+
|
68
|
+
def has_many_attribute?(relation)
|
69
|
+
reflect_association(relation).macro == :has_many
|
70
|
+
end
|
71
|
+
|
72
|
+
def belongs_to_attribute?(relation)
|
73
|
+
reflect_association(relation).macro == :belongs_to
|
74
|
+
end
|
75
|
+
|
76
|
+
def reflect_association(relation)
|
77
|
+
relation.klass.reflect_on_association(attribute.to_s)
|
78
|
+
end
|
44
79
|
end
|
45
80
|
end
|
@@ -15,6 +15,14 @@ module Administrate
|
|
15
15
|
@resource_path ||= resource_name.gsub("/", "_")
|
16
16
|
end
|
17
17
|
|
18
|
+
def collection_includes
|
19
|
+
dashboard.try(:collection_includes) || []
|
20
|
+
end
|
21
|
+
|
22
|
+
def item_includes
|
23
|
+
dashboard.try(:item_includes) || []
|
24
|
+
end
|
25
|
+
|
18
26
|
protected
|
19
27
|
|
20
28
|
def attribute_field(dashboard, resource, attribute_name, page)
|
@@ -21,7 +21,11 @@ module Administrate
|
|
21
21
|
ordered_by?(attr) && order.direction
|
22
22
|
end
|
23
23
|
|
24
|
-
delegate :ordered_by?,
|
24
|
+
delegate :ordered_by?, to: :order
|
25
|
+
|
26
|
+
def order_params_for(attr, key: resource_name)
|
27
|
+
{ key => order.order_params_for(attr) }
|
28
|
+
end
|
25
29
|
|
26
30
|
private
|
27
31
|
|
@@ -5,7 +5,7 @@ module Administrate
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def dashboard_class
|
8
|
-
|
8
|
+
ActiveSupport::Inflector.constantize("#{resource_class_name}Dashboard")
|
9
9
|
end
|
10
10
|
|
11
11
|
def namespace
|
@@ -13,7 +13,7 @@ module Administrate
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def resource_class
|
16
|
-
|
16
|
+
ActiveSupport::Inflector.constantize(resource_class_name)
|
17
17
|
end
|
18
18
|
|
19
19
|
def resource_name
|
data/lib/administrate/search.rb
CHANGED
@@ -3,32 +3,91 @@ require "active_support/core_ext/object/blank"
|
|
3
3
|
|
4
4
|
module Administrate
|
5
5
|
class Search
|
6
|
+
class Query
|
7
|
+
attr_reader :filters
|
8
|
+
|
9
|
+
def blank?
|
10
|
+
terms.blank? && filters.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(original_query)
|
14
|
+
@original_query = original_query
|
15
|
+
@filters, @terms = parse_query(original_query)
|
16
|
+
end
|
17
|
+
|
18
|
+
def original
|
19
|
+
@original_query
|
20
|
+
end
|
21
|
+
|
22
|
+
def terms
|
23
|
+
@terms.join(" ")
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
original
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def filter?(word)
|
33
|
+
word.match?(/^\w+:$/)
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_query(query)
|
37
|
+
filters = []
|
38
|
+
terms = []
|
39
|
+
query.to_s.split.each do |word|
|
40
|
+
if filter?(word)
|
41
|
+
filters << word.split(":").first
|
42
|
+
else
|
43
|
+
terms << word
|
44
|
+
end
|
45
|
+
end
|
46
|
+
[filters, terms]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
6
50
|
def initialize(scoped_resource, dashboard_class, term)
|
7
51
|
@dashboard_class = dashboard_class
|
8
52
|
@scoped_resource = scoped_resource
|
9
|
-
@
|
53
|
+
@query = Query.new(term)
|
10
54
|
end
|
11
55
|
|
12
56
|
def run
|
13
|
-
if
|
57
|
+
if query.blank?
|
14
58
|
@scoped_resource.all
|
15
59
|
else
|
16
|
-
@scoped_resource
|
60
|
+
results = search_results(@scoped_resource)
|
61
|
+
results = filter_results(results)
|
62
|
+
results
|
17
63
|
end
|
18
64
|
end
|
19
65
|
|
20
66
|
private
|
21
67
|
|
22
|
-
def
|
68
|
+
def apply_filter(filter, resources)
|
69
|
+
return resources unless filter
|
70
|
+
filter.call(resources)
|
71
|
+
end
|
72
|
+
|
73
|
+
def filter_results(resources)
|
74
|
+
query.filters.each do |filter_name|
|
75
|
+
filter = valid_filters[filter_name]
|
76
|
+
resources = apply_filter(filter, resources)
|
77
|
+
end
|
78
|
+
resources
|
79
|
+
end
|
80
|
+
|
81
|
+
def query_template
|
23
82
|
search_attributes.map do |attr|
|
24
|
-
table_name =
|
25
|
-
|
26
|
-
|
27
|
-
"
|
83
|
+
table_name = query_table_name(attr)
|
84
|
+
attr_name = column_to_query(attr)
|
85
|
+
|
86
|
+
"LOWER(CAST(#{table_name}.#{attr_name} AS CHAR(256))) LIKE ?"
|
28
87
|
end.join(" OR ")
|
29
88
|
end
|
30
89
|
|
31
|
-
def
|
90
|
+
def query_values
|
32
91
|
["%#{term.mb_chars.downcase}%"] * search_attributes.count
|
33
92
|
end
|
34
93
|
|
@@ -38,10 +97,62 @@ module Administrate
|
|
38
97
|
end
|
39
98
|
end
|
40
99
|
|
100
|
+
def search_results(resources)
|
101
|
+
resources.
|
102
|
+
joins(tables_to_join).
|
103
|
+
where(query_template, *query_values)
|
104
|
+
end
|
105
|
+
|
106
|
+
def valid_filters
|
107
|
+
if @dashboard_class.const_defined?(:COLLECTION_FILTERS)
|
108
|
+
@dashboard_class.const_get(:COLLECTION_FILTERS).stringify_keys
|
109
|
+
else
|
110
|
+
{}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
41
114
|
def attribute_types
|
42
115
|
@dashboard_class::ATTRIBUTE_TYPES
|
43
116
|
end
|
44
117
|
|
45
|
-
|
118
|
+
def query_table_name(attr)
|
119
|
+
if association_search?(attr)
|
120
|
+
ActiveRecord::Base.connection.quote_table_name(attr.to_s.pluralize)
|
121
|
+
else
|
122
|
+
ActiveRecord::Base.connection.
|
123
|
+
quote_table_name(@scoped_resource.table_name)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def column_to_query(attr)
|
128
|
+
if association_search?(attr)
|
129
|
+
ActiveRecord::Base.connection.
|
130
|
+
quote_column_name(attribute_types[attr].searchable_field)
|
131
|
+
else
|
132
|
+
ActiveRecord::Base.connection.quote_column_name(attr)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def tables_to_join
|
137
|
+
attribute_types.keys.select do |attribute|
|
138
|
+
attribute_types[attribute].searchable? && association_search?(attribute)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def association_search?(attribute)
|
143
|
+
return unless attribute_types[attribute].respond_to?(:deferred_class)
|
144
|
+
|
145
|
+
[
|
146
|
+
Administrate::Field::BelongsTo,
|
147
|
+
Administrate::Field::HasMany,
|
148
|
+
Administrate::Field::HasOne,
|
149
|
+
].include?(attribute_types[attribute].deferred_class)
|
150
|
+
end
|
151
|
+
|
152
|
+
def term
|
153
|
+
query.terms
|
154
|
+
end
|
155
|
+
|
156
|
+
attr_reader :resolver, :query
|
46
157
|
end
|
47
158
|
end
|