discerner 1.1.18
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +97 -0
- data/Rakefile +29 -0
- data/app/assets/images/discerner/add.png +0 -0
- data/app/assets/images/discerner/ajax-loader.gif +0 -0
- data/app/assets/images/discerner/bar.gif +0 -0
- data/app/assets/images/discerner/bullet_arrow_down.png +0 -0
- data/app/assets/images/discerner/bullet_arrow_up.png +0 -0
- data/app/assets/images/discerner/cog.png +0 -0
- data/app/assets/images/discerner/delete.png +0 -0
- data/app/assets/images/discerner/edit.png +0 -0
- data/app/assets/images/discerner/excel.png +0 -0
- data/app/assets/images/discerner/greencheck.gif +0 -0
- data/app/assets/images/discerner/rails.png +0 -0
- data/app/assets/images/discerner/show.png +0 -0
- data/app/assets/images/discerner/switch_minus.gif +0 -0
- data/app/assets/images/discerner/switch_plus.gif +0 -0
- data/app/assets/javascripts/discerner/application.js +20 -0
- data/app/assets/javascripts/discerner/combobox.js +301 -0
- data/app/assets/javascripts/discerner/discerner.js +19 -0
- data/app/assets/javascripts/discerner/export_parameters.js +13 -0
- data/app/assets/javascripts/discerner/jquery/jquery.blockUI.js +576 -0
- data/app/assets/javascripts/discerner/jquery/jquery.form.js +1074 -0
- data/app/assets/javascripts/discerner/nested_attributes.js +69 -0
- data/app/assets/javascripts/discerner/search_combinations.js +49 -0
- data/app/assets/javascripts/discerner/search_parameter.js +131 -0
- data/app/assets/javascripts/discerner/search_parameter_value.js +172 -0
- data/app/assets/javascripts/discerner/searches.js +93 -0
- data/app/assets/javascripts/discerner/url.js +42 -0
- data/app/assets/stylesheets/discerner/application.css +16 -0
- data/app/assets/stylesheets/discerner/buttons.sass +13 -0
- data/app/assets/stylesheets/discerner/categorized_autocompleter.sass +53 -0
- data/app/assets/stylesheets/discerner/discerner.sass +51 -0
- data/app/assets/stylesheets/discerner/export_parameters.sass +43 -0
- data/app/assets/stylesheets/discerner/links.sass +29 -0
- data/app/assets/stylesheets/discerner/searches.sass +205 -0
- data/app/assets/stylesheets/discerner/tables.sass +32 -0
- data/app/controllers/discerner/application_controller.rb +2 -0
- data/app/controllers/discerner/export_parameters_controller.rb +5 -0
- data/app/controllers/discerner/parameters_controller.rb +5 -0
- data/app/controllers/discerner/searches_controller.rb +5 -0
- data/app/helpers/discerner/application_helper.rb +4 -0
- data/app/helpers/discerner/parameters_helper.rb +5 -0
- data/app/helpers/discerner/searches_helper.rb +5 -0
- data/app/models/discerner/dictionary.rb +5 -0
- data/app/models/discerner/export_parameter.rb +5 -0
- data/app/models/discerner/operator.rb +5 -0
- data/app/models/discerner/parameter.rb +5 -0
- data/app/models/discerner/parameter_category.rb +5 -0
- data/app/models/discerner/parameter_type.rb +5 -0
- data/app/models/discerner/parameter_value.rb +5 -0
- data/app/models/discerner/parameter_value_categorization.rb +5 -0
- data/app/models/discerner/parameter_value_category.rb +5 -0
- data/app/models/discerner/search.rb +5 -0
- data/app/models/discerner/search_combination.rb +5 -0
- data/app/models/discerner/search_parameter.rb +5 -0
- data/app/models/discerner/search_parameter_value.rb +5 -0
- data/app/views/discerner/export_parameters/index.html.haml +55 -0
- data/app/views/discerner/parameters/_values_autocompleter.html.haml +49 -0
- data/app/views/discerner/parameters/values.html.haml +1 -0
- data/app/views/discerner/searches/_form.html.haml +21 -0
- data/app/views/discerner/searches/_form_combined_searches.html.haml +32 -0
- data/app/views/discerner/searches/_form_controls.html.haml +8 -0
- data/app/views/discerner/searches/_form_header.html.haml +39 -0
- data/app/views/discerner/searches/_form_search_parameters.html.haml +28 -0
- data/app/views/discerner/searches/_list.html.haml +17 -0
- data/app/views/discerner/searches/_search_combination_fields.html.haml +22 -0
- data/app/views/discerner/searches/_search_parameter_fields.html.haml +48 -0
- data/app/views/discerner/searches/_search_parameter_value_fields.html.haml +62 -0
- data/app/views/discerner/searches/_summary.html.haml +25 -0
- data/app/views/discerner/searches/edit.html.haml +8 -0
- data/app/views/discerner/searches/index.html.haml +13 -0
- data/app/views/discerner/searches/index.js.haml +1 -0
- data/app/views/discerner/searches/new.html.haml +3 -0
- data/app/views/discerner/searches/rename.html.haml +6 -0
- data/app/views/discerner/searches/update.js.haml +7 -0
- data/app/views/discerner/shared/_categorized_autocompleter_items.html.haml +15 -0
- data/app/views/discerner/shared/_error_messages.html.haml +5 -0
- data/app/views/layouts/discerner/searches.html.erb +17 -0
- data/config/cucumber.yml +8 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20121004040716_create_discerner_dictionaries.rb +11 -0
- data/db/migrate/20121004153043_create_discerner_parameter_categories.rb +12 -0
- data/db/migrate/20121005194843_create_discerner_parameter_types.rb +11 -0
- data/db/migrate/20121005203223_create_discerner_parameters.rb +14 -0
- data/db/migrate/20121008154855_create_discerner_operators.rb +13 -0
- data/db/migrate/20121008160313_create_discerner_operators_parameter_types.rb +8 -0
- data/db/migrate/20121008161455_create_discerner_parameter_values.rb +13 -0
- data/db/migrate/20121008180829_create_discerner_searches.rb +11 -0
- data/db/migrate/20121008182443_create_discerner_search_parameters.rb +11 -0
- data/db/migrate/20121011205130_create_discerner_search_parameter_values.rb +15 -0
- data/db/migrate/20121211213215_add_dictionary_id_to_discerner_searches.rb +5 -0
- data/db/migrate/20130205193602_create_discerner_search_combinations.rb +12 -0
- data/db/migrate/20130211230636_create_discerner_export_parameters.rb +9 -0
- data/db/migrate/20130213185818_add_search_columns_to_discerner_parameters.rb +38 -0
- data/db/migrate/20130213205255_rename_database_name_to_search_value_in_discerner_parameter_values.rb +5 -0
- data/db/migrate/20130215165416_add_searchable_to_discerner_parameters.rb +5 -0
- data/db/migrate/20130218230257_add_exclusive_to_discerner_parameters.rb +5 -0
- data/db/migrate/20130220163015_replace_integer_type_with_numeric.rb +22 -0
- data/db/migrate/20130221172826_add_unique_identifier_to_discerner_parameters.rb +5 -0
- data/db/migrate/20130222052924_change_search_attribute_to_method.rb +29 -0
- data/db/migrate/20130222070959_add_export_columns_to_discerner_parameters.rb +6 -0
- data/db/migrate/20130227031747_add_unique_identifier_to_discerner_operators.rb +16 -0
- data/db/migrate/20130306015019_change_discerner_parameter_values_name.rb +9 -0
- data/db/migrate/20130306212430_add_deleted_at_to_discerner_search_parameters.rb +5 -0
- data/db/migrate/20130306212504_add_deleted_at_to_discerner_search_parameter_values.rb +5 -0
- data/db/migrate/20130306212527_add_deleted_at_to_discerner_search_combinations.rb +5 -0
- data/db/migrate/20130306212818_add_deleted_at_to_discerner_export_parameters.rb +5 -0
- data/db/migrate/20130311190717_add_operator_type_to_discerner_operators.rb +5 -0
- data/db/migrate/20131212175110_remove_extra_search_parameter_values.rb +10 -0
- data/db/migrate/20140204170625_create_discerner_parameter_value_categories.rb +16 -0
- data/db/migrate/20140204170646_create_discerner_parameter_value_categorizations.rb +12 -0
- data/db/migrate/20140227191827_remove_blank_parameter_values_from_export_parameters.rb +10 -0
- data/db/seeds.rb +0 -0
- data/lib/discerner/engine.rb +16 -0
- data/lib/discerner/methods/controllers/export_parameters_controller.rb +38 -0
- data/lib/discerner/methods/controllers/parameters_controller.rb +30 -0
- data/lib/discerner/methods/controllers/searches_controller.rb +204 -0
- data/lib/discerner/methods/helpers/searches_helper.rb +145 -0
- data/lib/discerner/methods/models/dictionary.rb +54 -0
- data/lib/discerner/methods/models/export_parameter.rb +35 -0
- data/lib/discerner/methods/models/operator.rb +42 -0
- data/lib/discerner/methods/models/parameter.rb +90 -0
- data/lib/discerner/methods/models/parameter_category.rb +60 -0
- data/lib/discerner/methods/models/parameter_type.rb +33 -0
- data/lib/discerner/methods/models/parameter_value.rb +87 -0
- data/lib/discerner/methods/models/parameter_value_categorization.rb +21 -0
- data/lib/discerner/methods/models/parameter_value_category.rb +45 -0
- data/lib/discerner/methods/models/search.rb +147 -0
- data/lib/discerner/methods/models/search_combination.rb +50 -0
- data/lib/discerner/methods/models/search_parameter.rb +128 -0
- data/lib/discerner/methods/models/search_parameter_value.rb +130 -0
- data/lib/discerner/methods/models/soft_delete.rb +35 -0
- data/lib/discerner/methods/models/warning.rb +15 -0
- data/lib/discerner/parser.rb +497 -0
- data/lib/discerner/version.rb +3 -0
- data/lib/discerner.rb +4 -0
- data/lib/generators/discerner/dictionary/dictionary_generator.rb +38 -0
- data/lib/generators/discerner/dictionary/templates/model.rb +15 -0
- data/lib/generators/discerner/dictionary/templates/show.xls.erb +37 -0
- data/lib/generators/discerner/dictionary/templates/view.html.haml +2 -0
- data/lib/generators/discerner/install/install_generator.rb +153 -0
- data/lib/generators/discerner/install/templates/controllers/export_parameters_controller.rb +20 -0
- data/lib/generators/discerner/install/templates/controllers/parameters_controller.rb +15 -0
- data/lib/generators/discerner/install/templates/controllers/searches_controller.rb +39 -0
- data/lib/generators/discerner/install/templates/dictionaries.yml +236 -0
- data/lib/generators/discerner/install/templates/helpers/searches_helper.rb +9 -0
- data/lib/generators/discerner/install/templates/models/book.rb +15 -0
- data/lib/generators/discerner/install/templates/models/dictionary.rb +9 -0
- data/lib/generators/discerner/install/templates/models/export_parameter.rb +9 -0
- data/lib/generators/discerner/install/templates/models/operator.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter.rb +10 -0
- data/lib/generators/discerner/install/templates/models/parameter_category.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_type.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_value.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_value_categorization.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_value_category.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search_combination.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search_parameter.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search_parameter_value.rb +9 -0
- data/lib/generators/discerner/install/templates/views/layouts/searches.html.erb +17 -0
- data/lib/setup/operators.yml +91 -0
- data/lib/tasks/cucumber.rake +65 -0
- data/lib/tasks/discerner_tasks.rake +30 -0
- metadata +531 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module ExportParameter
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :belongs_to, :parameter, :inverse_of => :export_parameters
|
|
10
|
+
base.send :belongs_to, :search, :inverse_of => :export_parameters
|
|
11
|
+
|
|
12
|
+
# Scopes
|
|
13
|
+
base.send(:scope, :ordered, -> { base.order('discerner_export_parameters.id ASC') })
|
|
14
|
+
base.send(:scope, :by_parameter_category, ->(parameter_category) { base.includes(:parameter).where('discerner_parameters.parameter_category_id' => parameter_category.id) unless parameter_category.blank?})
|
|
15
|
+
|
|
16
|
+
# Validations
|
|
17
|
+
base.send :validates, :parameter, :search, :presence => { :message => "for export parameter can't be blank" }
|
|
18
|
+
|
|
19
|
+
# Whitelisting attributes
|
|
20
|
+
base.send :attr_accessible, :parameter_id, :search_id, :parameter, :search
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Instance Methods
|
|
24
|
+
def initialize(*args)
|
|
25
|
+
super(*args)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def disabled?
|
|
29
|
+
return false unless persisted?
|
|
30
|
+
deleted? || parameter.blank? || parameter.deleted?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module Operator
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :has_many, :search_parameter_values, :inverse_of => :operator
|
|
10
|
+
base.send :has_many, :search_combinations, :inverse_of => :operator
|
|
11
|
+
base.send :has_and_belongs_to_many, :parameter_types, :join_table => :discerner_operators_parameter_types
|
|
12
|
+
|
|
13
|
+
# Validations
|
|
14
|
+
base.send :validates, :symbol, :presence => true, :uniqueness => {:message => "for operator has already been taken"}
|
|
15
|
+
base.send :validates, :operator_type, :presence => true
|
|
16
|
+
base.send :validate, :type_supported?
|
|
17
|
+
|
|
18
|
+
# Whitelisting attributes
|
|
19
|
+
base.send :attr_accessible, :operator_type, :symbol, :text, :deleted_at
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Instance Methods
|
|
23
|
+
def initialize(*args)
|
|
24
|
+
super(*args)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def css_class_name
|
|
28
|
+
css_class = parameter_types.map{ |t| t.name }
|
|
29
|
+
css_class << operator_type unless operator_type.blank?
|
|
30
|
+
css_class.join(' ')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
def type_supported?
|
|
35
|
+
return if self.operator_type.blank?
|
|
36
|
+
supported_types = ['comparison', 'text_comparison', 'range', 'list', 'presence']
|
|
37
|
+
errors.add(:base,"Operator type '#{self.operator_type}' is not supported, please use one of the following types: #{supported_types.join(', ')}") unless supported_types.include?(self.operator_type)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module Parameter
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :belongs_to, :parameter_category, :inverse_of => :parameters
|
|
10
|
+
base.send :belongs_to, :parameter_type, :inverse_of => :parameters
|
|
11
|
+
base.send :has_many, :parameter_values, :inverse_of => :parameter, :dependent => :destroy
|
|
12
|
+
base.send :has_many, :search_parameters, :inverse_of => :parameter, :dependent => :destroy
|
|
13
|
+
base.send :has_many, :export_parameters, :inverse_of => :parameter, :dependent => :destroy
|
|
14
|
+
base.send :has_many, :parameter_value_categories, :inverse_of => :parameter, :dependent => :destroy
|
|
15
|
+
|
|
16
|
+
#Validations
|
|
17
|
+
base.send :validates, :name, :unique_identifier, :parameter_category, :presence => { :message => "for parameter can't be blank" }
|
|
18
|
+
base.send :validate, :validate_unique_identifier
|
|
19
|
+
base.send :validate, :validate_search_attributes
|
|
20
|
+
base.send :validate, :validate_export_attributes
|
|
21
|
+
|
|
22
|
+
# Scopes
|
|
23
|
+
base.send(:scope, :searchable, -> {base.not_deleted.where('search_model is not null and search_method is not null')})
|
|
24
|
+
base.send(:scope, :exportable, -> {base.not_deleted.where('export_model is not null and export_method is not null')})
|
|
25
|
+
|
|
26
|
+
# Hooks
|
|
27
|
+
base.send :after_commit, :cascade_delete_parameter_values, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
|
28
|
+
|
|
29
|
+
# Whitelisting attributes
|
|
30
|
+
base.send :attr_accessible, :name, :parameter_category, :parameter_category_id, :parameter_type, :parameter_type_id,
|
|
31
|
+
:search_model, :search_method, :unique_identifier, :export_model, :export_method
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Instance Methods
|
|
35
|
+
def initialize(*args)
|
|
36
|
+
super(*args)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def used_in_search?
|
|
40
|
+
search_parameters.any? || export_parameters.any?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def display_name
|
|
44
|
+
"#{parameter_category.name} - #{name}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def css_class_name
|
|
48
|
+
css_class_array = [parameter_type.name, parameter_category.css_class_name, parameter_category.dictionary.css_class_name]
|
|
49
|
+
css_class_array << 'exclusive' if exclusive
|
|
50
|
+
css_class_array.join(' ')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
def validate_search_parameters
|
|
55
|
+
errors.add(:base,"Search should have at least one search criteria.") if
|
|
56
|
+
self.search_parameters.size < 1 || self.search_parameters.all?{|search_parameter| search_parameter.marked_for_destruction? }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def validate_unique_identifier
|
|
60
|
+
return if self.parameter_category.blank?
|
|
61
|
+
existing_parameters = Discerner::Parameter.
|
|
62
|
+
joins({ :parameter_category => :dictionary }).
|
|
63
|
+
where('discerner_dictionaries.id = ? and discerner_parameters.unique_identifier = ?', self.parameter_category.dictionary.id, self.unique_identifier)
|
|
64
|
+
existing_parameters = existing_parameters.where('discerner_parameters.id != ?', self.id) unless self.id.blank?
|
|
65
|
+
errors.add(:base,"Unique identifier has to be unique within dictionary.") if existing_parameters.any?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def validate_search_attributes
|
|
69
|
+
unless self.search_model.blank? && self.search_method.blank?
|
|
70
|
+
errors.add(:base,"Searchable parameter should have search model, search method and parameter_type defined.") if self.search_model.blank? || self.search_method.blank? || self.parameter_type.blank?
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def validate_export_attributes
|
|
75
|
+
unless self.export_model.blank? && self.export_method.blank?
|
|
76
|
+
errors.add(:base,"Exportable parameter should have export model and search method defined.") if self.export_model.blank? || self.export_method.blank?
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def cascade_delete_parameter_values
|
|
81
|
+
return unless deleted?
|
|
82
|
+
parameter_values.each do |pv|
|
|
83
|
+
pv.deleted_at = Time.now
|
|
84
|
+
pv.save
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module ParameterCategory
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :belongs_to, :dictionary, :inverse_of => :parameter_categories
|
|
10
|
+
base.send :has_many, :parameters, :inverse_of => :parameter_category, :dependent => :destroy
|
|
11
|
+
|
|
12
|
+
# Validations
|
|
13
|
+
base.send :validates, :name, :presence => true, :uniqueness => { :scope => :dictionary_id, :message => "for parameter category has already been taken"}
|
|
14
|
+
base.send :validates, :dictionary, :presence => { :message => "for parameter category can't be blank" }
|
|
15
|
+
|
|
16
|
+
# Scopes
|
|
17
|
+
base.send(:scope, :searchable, -> {base.includes(:parameters).where('discerner_parameters.search_model is not null and discerner_parameters.search_method is not null and discerner_parameters.deleted_at is null')})
|
|
18
|
+
base.send(:scope, :exportable, -> {base.includes(:parameters).where('discerner_parameters.export_model is not null and discerner_parameters.export_method is not null and discerner_parameters.deleted_at is null')})
|
|
19
|
+
base.send(:scope, :ordered_by_name, -> {base.order('discerner_parameter_categories.name ASC')})
|
|
20
|
+
|
|
21
|
+
# Hooks
|
|
22
|
+
base.send :after_commit, :cascade_delete_parameters, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
|
23
|
+
|
|
24
|
+
# Whitelisting attributes
|
|
25
|
+
base.send :attr_accessible, :deleted_at, :dictionary, :dictionary_id, :name
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Instance Methods
|
|
29
|
+
def initialize(*args)
|
|
30
|
+
super(*args)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def parameterized_name
|
|
34
|
+
name.parameterize.underscore
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def searchable_parameters
|
|
38
|
+
parameters.searchable
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def exportable_parameters
|
|
42
|
+
parameters.exportable
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def css_class_name
|
|
46
|
+
"parameter_category_#{parameterized_name}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
def cascade_delete_parameters
|
|
51
|
+
return unless deleted?
|
|
52
|
+
parameters.each do |p|
|
|
53
|
+
p.deleted_at = Time.now
|
|
54
|
+
p.save
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module ParameterType
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :has_many, :parameters, :inverse_of => :parameter_type
|
|
10
|
+
base.send :has_and_belongs_to_many, :operators, :join_table => :discerner_operators_parameter_types
|
|
11
|
+
|
|
12
|
+
# Validations
|
|
13
|
+
base.send :validates, :name, :presence => true, :uniqueness => {:message => "for parameter type has already been taken"}
|
|
14
|
+
base.send :validate, :name_supported?
|
|
15
|
+
|
|
16
|
+
# Whitelisting attributes
|
|
17
|
+
base.send :attr_accessible, :deleted_at, :name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Instance Methods
|
|
21
|
+
def initialize(*args)
|
|
22
|
+
super(*args)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def name_supported?
|
|
26
|
+
return if self.name.blank?
|
|
27
|
+
supported_types = ['numeric', 'date', 'list', 'combobox', 'text', 'string', 'search']
|
|
28
|
+
errors.add(:base,"Parameter type '#{self.name}' is not supported, please use one of the following types: #{supported_types.join(', ')}") unless supported_types.include?(self.name)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module ParameterValue
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :belongs_to, :parameter, :inverse_of => :parameter_values
|
|
10
|
+
base.send :has_many, :search_parameter_values, :inverse_of => :parameter_value, :dependent => :destroy
|
|
11
|
+
base.send :has_one, :parameter_value_categorization, :inverse_of => :parameter_value, :dependent => :destroy
|
|
12
|
+
base.send :has_one, :parameter_value_category, :through=> :parameter_value_categorization
|
|
13
|
+
|
|
14
|
+
# Scopes
|
|
15
|
+
base.send(:scope, :ordered_by_name, -> { base.order('discerner_parameter_values.name ASC') })
|
|
16
|
+
base.send(:scope, :ordered_by_parameter_and_name, -> { base.order('discerner_parameter_values.parameter_id ASC, discerner_parameter_values.name ASC') })
|
|
17
|
+
|
|
18
|
+
#Validations
|
|
19
|
+
base.send :validates, :parameter, :presence => true
|
|
20
|
+
base.send :validates, :search_value, :length => { :maximum => 1000 }, :uniqueness => {:scope => :parameter_id, :message => "for parameter value has already been taken"}
|
|
21
|
+
base.send :validates, :name, :presence => true, :length => { :maximum => 1000 }
|
|
22
|
+
base.send :validate, :parameter_category_belongs_to_parameter
|
|
23
|
+
|
|
24
|
+
# Hooks
|
|
25
|
+
base.send :after_commit, :create_search_parameter_values, :on => :create
|
|
26
|
+
base.send :after_commit, :update_search_parameter_values, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
|
27
|
+
base.send :scope, :categorized, -> {base.joins(:parameter_value_category)}
|
|
28
|
+
base.send :scope, :uncategorized, -> {base.includes(:parameter_value_category).where(:discerner_parameter_value_categories => {:name => nil})}
|
|
29
|
+
|
|
30
|
+
# Whitelisting attributes
|
|
31
|
+
base.send :attr_accessible, :search_value, :name, :parameter, :parameter_id
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Instance Methods
|
|
35
|
+
def initialize(*args)
|
|
36
|
+
super(*args)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def used_in_search?
|
|
40
|
+
if parameter.parameter_type.name == 'list'
|
|
41
|
+
search_parameter_values.chosen.any?
|
|
42
|
+
else
|
|
43
|
+
search_parameter_values.any?
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def display_name
|
|
48
|
+
if parameter_value_category
|
|
49
|
+
"#{parameter_value_category.name} - #{name} "
|
|
50
|
+
else
|
|
51
|
+
name
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
def parameter_category_belongs_to_parameter
|
|
57
|
+
unless parameter_value_category.blank?
|
|
58
|
+
errors.add(:base,"Parameter category #{parameter_value_category.name} does not belong to parameter #{parameter.name}") unless parameter_value_category.parameter_id == parameter.id
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def create_search_parameter_values
|
|
63
|
+
# create additional search_parameter_values for list search_parameters so they can be dislayed as nested attribures
|
|
64
|
+
return if parameter.blank? || parameter.parameter_type.blank?
|
|
65
|
+
if parameter.parameter_type.name == 'list'
|
|
66
|
+
parameter.search_parameters.each do |sp|
|
|
67
|
+
if sp.search_parameter_values.where(:parameter_value_id => id).blank?
|
|
68
|
+
max_display_order = sp.search_parameter_values.ordered_by_display_order.last.display_order || -1
|
|
69
|
+
sp.search_parameter_values.build(:parameter_value_id => id, :display_order => max_display_order + 1)
|
|
70
|
+
sp.save
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def update_search_parameter_values
|
|
77
|
+
create_search_parameter_values
|
|
78
|
+
# destroy search_parameter_values that reference this value but are not chosen (list options)
|
|
79
|
+
return unless deleted?
|
|
80
|
+
search_parameter_values.each do |spv|
|
|
81
|
+
spv.destroy if parameter.parameter_type.name == 'list' && !spv.chosen
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module ParameterValueCategorization
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :belongs_to, :parameter_value_category, :inverse_of => :parameter_value_categorizations
|
|
10
|
+
base.send :belongs_to, :parameter_value, :inverse_of => :parameter_value_categorization
|
|
11
|
+
|
|
12
|
+
# Validations
|
|
13
|
+
base.send :validates_presence_of, :parameter_value_category, :parameter_value
|
|
14
|
+
|
|
15
|
+
# Whitelisting attributes
|
|
16
|
+
base.send :attr_accessible, :parameter_value_category_id, :parameter_value_id, :parameter_value_category, :parameter_value
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module ParameterValueCategory
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
|
|
8
|
+
# Associations
|
|
9
|
+
base.send :belongs_to, :parameter, :inverse_of => :parameter_value_categories
|
|
10
|
+
base.send :has_many, :parameter_value_categorizations, :dependent => :destroy
|
|
11
|
+
base.send :has_many, :parameter_values, :through => :parameter_value_categorizations
|
|
12
|
+
|
|
13
|
+
# Scopes
|
|
14
|
+
base.send(:scope, :ordered_by_name, -> { base.order('discerner_parameter_value_categories.name ASC') })
|
|
15
|
+
base.send(:scope, :ordered_by_display_order_and_name, -> { base.order('discerner_parameter_value_categories.display_order ASC, discerner_parameter_value_categories.name ASC') })
|
|
16
|
+
|
|
17
|
+
# Validations
|
|
18
|
+
base.send :validates_presence_of, :parameter, :unique_identifier, :name
|
|
19
|
+
base.send :validates, :unique_identifier, :uniqueness => {:scope => [:parameter_id, :deleted_at], :message => "for parameter value category has already been taken"}
|
|
20
|
+
base.send :validate, :parameter_value_belongs_to_parameter
|
|
21
|
+
|
|
22
|
+
# Whitelisting attributes
|
|
23
|
+
base.send :attr_accessible, :parameter, :parameter_id, :unique_identifier, :name
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def css_class
|
|
27
|
+
"parameter_value_category_#{parameterized_name}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def parameterized_name
|
|
31
|
+
name.parameterize.underscore
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
def parameter_value_belongs_to_parameter
|
|
36
|
+
unless parameter.blank?
|
|
37
|
+
parameter_values.each do |parameter_value|
|
|
38
|
+
errors.add(:base,"Parameter value #{parameter_value.name} does not belong to parameter #{parameter.name}") unless parameter_value.parameter_id == parameter.id
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module Search
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
base.send :include, Warning
|
|
8
|
+
|
|
9
|
+
# Associations
|
|
10
|
+
base.send :belongs_to, :dictionary
|
|
11
|
+
base.send :has_many, :search_parameters, :inverse_of => :search
|
|
12
|
+
base.send :has_many, :search_combinations, :inverse_of => :search
|
|
13
|
+
base.send :has_many, :combined_searches, :through => :search_combinations
|
|
14
|
+
base.send :has_many, :export_parameters, :inverse_of => :search
|
|
15
|
+
|
|
16
|
+
# Validations
|
|
17
|
+
base.send :validates, :dictionary, :presence => { :message => "for search can't be blank" }
|
|
18
|
+
base.send :validate, :validate_search_parameters
|
|
19
|
+
|
|
20
|
+
# Scopes
|
|
21
|
+
base.send(:scope, :by_user, ->(username) { base.where(:username => username) unless username.blank?})
|
|
22
|
+
|
|
23
|
+
# Nested attributes
|
|
24
|
+
base.send :accepts_nested_attributes_for, :search_parameters, :allow_destroy => true,
|
|
25
|
+
:reject_if => proc { |attributes| attributes['parameter_id'].blank? && attributes['parameter'].blank? }
|
|
26
|
+
|
|
27
|
+
base.send :accepts_nested_attributes_for, :search_combinations, :allow_destroy => true,
|
|
28
|
+
:reject_if => proc { |attributes| attributes['combined_search_id'].blank? && attributes['combined_search'].blank? }
|
|
29
|
+
|
|
30
|
+
# Hooks
|
|
31
|
+
base.send :after_commit, :update_associations, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
|
32
|
+
|
|
33
|
+
# Whitelisting attributes
|
|
34
|
+
base.send :attr_accessible, :deleted_at, :name, :username, :search_parameters, :search_parameters_attributes,
|
|
35
|
+
:dictionary, :dictionary_id, :search_combinations_attributes
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Instance Methods
|
|
39
|
+
def initialize(*args)
|
|
40
|
+
super(*args)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def display_name
|
|
44
|
+
name.blank? ? "[No name specified]" : name
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def parameterized_name
|
|
48
|
+
display_name.parameterize.underscore
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def traverse
|
|
52
|
+
return unless combined_searches.any?
|
|
53
|
+
searches = []
|
|
54
|
+
combined_searches.each do |s|
|
|
55
|
+
searches << s
|
|
56
|
+
nested_searches = s.traverse
|
|
57
|
+
searches << nested_searches unless nested_searches.blank?
|
|
58
|
+
end
|
|
59
|
+
searches
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def nested_searches
|
|
63
|
+
nested_searches = traverse || []
|
|
64
|
+
nested_searches.flatten.compact
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def parameter_categories
|
|
68
|
+
search_parameters.map{|p| p.parameter.parameter_category unless p.parameter.blank?}.uniq
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_conditions
|
|
72
|
+
search_models = {}
|
|
73
|
+
all_search_parameters = nested_searches.map { |ns| ns.search_parameters }.flatten
|
|
74
|
+
all_search_parameters.concat(search_parameters).flatten!
|
|
75
|
+
|
|
76
|
+
all_search_parameters.each do |search_parameter|
|
|
77
|
+
search_models[search_parameter.parameter.search_model] = { :search_parameters => [], :conditions => nil } unless search_models.has_key?(search_parameter.parameter.search_model)
|
|
78
|
+
search_models[search_parameter.parameter.search_model][:search_parameters] << search_parameter
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
search_models.each do |k,v|
|
|
82
|
+
predicates = []
|
|
83
|
+
arguments = []
|
|
84
|
+
|
|
85
|
+
v[:search_parameters].each do |search_parameter|
|
|
86
|
+
sql = search_parameter.to_sql unless search_parameter.search_parameter_values.empty?
|
|
87
|
+
unless sql.nil?
|
|
88
|
+
predicates << sql[:predicates]
|
|
89
|
+
arguments << sql[:values] unless sql[:values].blank?
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
search_models[k][:conditions] = [predicates.join(' and '), *flatten_arguments(arguments)]
|
|
94
|
+
end
|
|
95
|
+
search_models
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def flatten_arguments(arguments)
|
|
99
|
+
args = []
|
|
100
|
+
arguments.each do |a|
|
|
101
|
+
a.each do |b|
|
|
102
|
+
args << b
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
args
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def disabled?
|
|
109
|
+
return false unless persisted?
|
|
110
|
+
if export_parameters.select{|ep| ep.disabled?}.any?
|
|
111
|
+
warnings.add(:base, "Search uses deleted export parameters")
|
|
112
|
+
return true
|
|
113
|
+
end
|
|
114
|
+
deleted? ||
|
|
115
|
+
dictionary.deleted? ||
|
|
116
|
+
search_parameters.select{|sp| sp.disabled?}.any? ||
|
|
117
|
+
search_combinations.select{|sc| sc.disabled?}.any?
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def searched_model?(model_name)
|
|
121
|
+
conditions.has_key?(model_name)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def conditions(force=false)
|
|
125
|
+
@conditions = self.to_conditions if @conditions.blank? || force
|
|
126
|
+
@conditions
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
def validate_search_parameters
|
|
131
|
+
if self.search_parameters.size < 1 || self.search_parameters.all?{|search_parameter| search_parameter.marked_for_destruction? }
|
|
132
|
+
errors.add(:base,"Search should have at least one search criteria.")
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def update_associations
|
|
137
|
+
[search_parameters, export_parameters, search_combinations].each do |accociated_records|
|
|
138
|
+
accociated_records.each do |r|
|
|
139
|
+
r.deleted_at = Time.now
|
|
140
|
+
r.save
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Discerner
|
|
2
|
+
module Methods
|
|
3
|
+
module Models
|
|
4
|
+
module SearchCombination
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.send :include, SoftDelete
|
|
7
|
+
base.send :include, Warning
|
|
8
|
+
|
|
9
|
+
# Associations
|
|
10
|
+
base.send :belongs_to, :operator, :inverse_of => :search_combinations
|
|
11
|
+
base.send :belongs_to, :search, :inverse_of => :search_combinations, :foreign_key => :search_id
|
|
12
|
+
base.send :belongs_to, :combined_search, :foreign_key => :combined_search_id, :class_name => 'Discerner::Search'
|
|
13
|
+
|
|
14
|
+
# Scopes
|
|
15
|
+
base.send(:scope, :ordered_by_display_order, -> { base.order('discerner_search_combinations.display_order ASC') })
|
|
16
|
+
|
|
17
|
+
# Validations
|
|
18
|
+
base.send :validates_presence_of, :search, :combined_search
|
|
19
|
+
base.send :validate, :validate_searches
|
|
20
|
+
|
|
21
|
+
# Whitelisting attributes
|
|
22
|
+
base.send :attr_accessible, :combined_search_id, :display_order, :operator_id, :search_id, :search, :combined_search
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Instance Methods
|
|
26
|
+
def initialize(*args)
|
|
27
|
+
super(*args)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def validate_searches
|
|
31
|
+
return if self.search_id.blank? || self.combined_search_id.blank?
|
|
32
|
+
errors.add(:base,"Search cannot be combined with itself.") if self.search_id == self.combined_search_id
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def disabled?
|
|
36
|
+
return false unless persisted?
|
|
37
|
+
return true if deleted?
|
|
38
|
+
if combined_search.deleted?
|
|
39
|
+
warnings.add(:base, "Combined search has been deleted and has to be removed from the search")
|
|
40
|
+
return true
|
|
41
|
+
elsif combined_search.disabled?
|
|
42
|
+
warnings.add(:base, "Combined search has been disabled and has to be removed from the search")
|
|
43
|
+
return true
|
|
44
|
+
end
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|