question_chain 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 +18 -0
- data/Licence.txt +20 -0
- data/README.rdoc +34 -0
- data/Rakefile +2 -0
- data/config/initializers/mustache.rb +2 -0
- data/lib/question_chain/answerable.rb +142 -0
- data/lib/question_chain/answers.rb +290 -0
- data/lib/question_chain/models/answers/question_view.rb +21 -0
- data/lib/question_chain/models/answers/ui_object_view.rb +67 -0
- data/lib/question_chain/models/answers/ui_objects_check_box_view.rb +17 -0
- data/lib/question_chain/models/answers/ui_objects_drop_down_view.rb +16 -0
- data/lib/question_chain/models/answers/ui_objects_hidden_field_view.rb +8 -0
- data/lib/question_chain/models/answers/ui_objects_object_reference_drop_down_view.rb +18 -0
- data/lib/question_chain/models/answers/ui_objects_object_search_view.rb +22 -0
- data/lib/question_chain/models/answers/ui_objects_relatable_category_drop_down_view.rb +18 -0
- data/lib/question_chain/models/answers/ui_objects_text_field_view.rb +8 -0
- data/lib/question_chain/models/chain_template.rb +43 -0
- data/lib/question_chain/models/question.rb +37 -0
- data/lib/question_chain/models/relatable_category_filter.rb +15 -0
- data/lib/question_chain/models/rule.rb +27 -0
- data/lib/question_chain/models/rules/attribute_change.rb +28 -0
- data/lib/question_chain/models/rules/choice_genenerator.rb +5 -0
- data/lib/question_chain/models/rules/populate_drop_down.rb +30 -0
- data/lib/question_chain/models/rules/search.rb +19 -0
- data/lib/question_chain/models/rules/value_change.rb +22 -0
- data/lib/question_chain/models/ui_group.rb +71 -0
- data/lib/question_chain/models/ui_object.rb +92 -0
- data/lib/question_chain/models/ui_object_answer.rb +17 -0
- data/lib/question_chain/models/ui_objects/check_box.rb +8 -0
- data/lib/question_chain/models/ui_objects/drop_down.rb +17 -0
- data/lib/question_chain/models/ui_objects/hidden_field.rb +5 -0
- data/lib/question_chain/models/ui_objects/object_reference_drop_down.rb +67 -0
- data/lib/question_chain/models/ui_objects/object_search.rb +44 -0
- data/lib/question_chain/models/ui_objects/radio_button.rb +5 -0
- data/lib/question_chain/models/ui_objects/radio_button_group.rb +5 -0
- data/lib/question_chain/models/ui_objects/relatable_category_drop_down.rb +70 -0
- data/lib/question_chain/models/ui_objects/text_field.rb +11 -0
- data/lib/question_chain/mongo_serialization.rb +62 -0
- data/lib/question_chain/mustache_handler.rb +16 -0
- data/lib/question_chain/mustache_rails.rb +50 -0
- data/lib/question_chain/state_machine.rb +29 -0
- data/lib/question_chain/stored_template.rb +30 -0
- data/lib/question_chain/version.rb +3 -0
- data/lib/question_chain/views/answers/_edit.html.haml +62 -0
- data/lib/question_chain/views/answers/_new.html.haml +62 -0
- data/lib/question_chain/views/answers/_question.html.mustache +11 -0
- data/lib/question_chain/views/answers/_ui_objects_check_box.html.mustache +19 -0
- data/lib/question_chain/views/answers/_ui_objects_drop_down.html.mustache +26 -0
- data/lib/question_chain/views/answers/_ui_objects_hidden_field.html.mustache +3 -0
- data/lib/question_chain/views/answers/_ui_objects_object_reference_drop_down.html.mustache +27 -0
- data/lib/question_chain/views/answers/_ui_objects_object_search.html.mustache +20 -0
- data/lib/question_chain/views/answers/_ui_objects_relatable_category_drop_down.html.mustache +26 -0
- data/lib/question_chain/views/answers/_ui_objects_text_field.html.mustache +19 -0
- data/lib/question_chain/views/layouts/application.html.haml +10 -0
- data/lib/question_chain.rb +35 -0
- data/question_chain.gemspec +31 -0
- data/test_app/.gitignore +4 -0
- data/test_app/Gemfile +29 -0
- data/test_app/Rakefile +16 -0
- data/test_app/app/controllers/answers_controller.rb +13 -0
- data/test_app/app/controllers/application_controller.rb +4 -0
- data/test_app/app/models/container.rb +10 -0
- data/test_app/app/models/flight.rb +20 -0
- data/test_app/app/views/answers/edit.html.haml +1 -0
- data/test_app/app/views/answers/new.html.haml +1 -0
- data/test_app/config/application.rb +18 -0
- data/test_app/config/boot.rb +13 -0
- data/test_app/config/database.yml +15 -0
- data/test_app/config/environment.rb +5 -0
- data/test_app/config/initializers/app.rb +5 -0
- data/test_app/config/initializers/cookie_verification_secret.rb +7 -0
- data/test_app/config/initializers/mongodb.rb +2 -0
- data/test_app/config/initializers/session_store.rb +3 -0
- data/test_app/config/routes.rb +30 -0
- data/test_app/config.ru +2 -0
- data/test_app/environments/development.rb +19 -0
- data/test_app/environments/test.rb +30 -0
- data/test_app/lib/tasks/rspec.rake +69 -0
- data/test_app/lib/tasks/yard.rake +4 -0
- data/test_app/public/.gitkeep +0 -0
- data/test_app/script/rails +10 -0
- data/test_app/spec/acceptance/new_spec +30 -0
- data/test_app/spec/factories.rb +81 -0
- data/test_app/spec/models/chain_template_spec.rb +53 -0
- data/test_app/spec/models/flight_spec.rb +101 -0
- data/test_app/spec/models/question_spec.rb +13 -0
- data/test_app/spec/models/rules/value_change_spec.rb +31 -0
- data/test_app/spec/models/ui_group_spec.rb +55 -0
- data/test_app/spec/models/ui_object_spec.rb +33 -0
- data/test_app/spec/models/ui_objects/drop_down_spec.rb +28 -0
- data/test_app/spec/models/ui_objects/relatable_category_drop_down_spec.rb +13 -0
- data/test_app/spec/spec_helper.rb +25 -0
- metadata +325 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
source "http://rubygems.org"
|
|
2
|
+
|
|
3
|
+
gemspec
|
|
4
|
+
|
|
5
|
+
# Will automatically pull in this gem and all its
|
|
6
|
+
# dependencies specified in the gemspec
|
|
7
|
+
gem "question_chain", :path => File.expand_path("..", __FILE__)
|
|
8
|
+
gem "yard"
|
|
9
|
+
|
|
10
|
+
# These are development dependencies
|
|
11
|
+
group :test do
|
|
12
|
+
gem "rake"
|
|
13
|
+
gem "rspec", "2.5.0"
|
|
14
|
+
gem 'vcr', '~> 1.5', :require => false
|
|
15
|
+
gem 'webmock', '~> 1.6', :require => false
|
|
16
|
+
gem "autotest"
|
|
17
|
+
end
|
|
18
|
+
|
data/Licence.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2008-2010 Richard Hooker - richard.hookere@carboncalculated.com
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
= QuestionChain
|
|
2
|
+
|
|
3
|
+
== What Am I?
|
|
4
|
+
|
|
5
|
+
This is not to be used currently! Work in Progress; Extracting not quite complete and SPECS
|
|
6
|
+
|
|
7
|
+
There will be guides on how to use this http://guides.carboncalculated.com
|
|
8
|
+
|
|
9
|
+
This is a Rails3 Gem to be used in conjunction with the soon to be released QuestionChainJS library
|
|
10
|
+
to be used with the CarbonCalculated API http://carboncalculated.com
|
|
11
|
+
|
|
12
|
+
This Gem allows you to create a forms for Carbon Calculations in like 2 sometimes 3 minutes depending on typing speed
|
|
13
|
+
|
|
14
|
+
At the minute this has dependencies on MongoMapper currently thinking about moving to more ORM agnostic approach
|
|
15
|
+
|
|
16
|
+
== Getting started
|
|
17
|
+
|
|
18
|
+
== UiObjects
|
|
19
|
+
|
|
20
|
+
=== Drop Downs
|
|
21
|
+
|
|
22
|
+
=== Object Reference Drop Downs
|
|
23
|
+
|
|
24
|
+
=== Rules
|
|
25
|
+
|
|
26
|
+
=== Attribute Change
|
|
27
|
+
|
|
28
|
+
=== Search
|
|
29
|
+
|
|
30
|
+
=== Markup
|
|
31
|
+
|
|
32
|
+
=== CSS
|
|
33
|
+
|
|
34
|
+
=== Bundling
|
data/Rakefile
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module QuestionChain
|
|
2
|
+
module Answerable
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
include MongoMapper::Serialize
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
key :question_id, ObjectId
|
|
8
|
+
key :result, Hash
|
|
9
|
+
key :answer_params, Hash
|
|
10
|
+
key :answer_json, String
|
|
11
|
+
key :user_id, ObjectId
|
|
12
|
+
key :reference, String
|
|
13
|
+
key :stored_identifier, String
|
|
14
|
+
key :stored_variable_input, String
|
|
15
|
+
key :created_by, String
|
|
16
|
+
key :_extra_keywords, Array
|
|
17
|
+
timestamps!
|
|
18
|
+
|
|
19
|
+
cattr_accessor :_extra_keyword_methods
|
|
20
|
+
before_save :add_stored_identifier
|
|
21
|
+
before_save :add_extra_keywords
|
|
22
|
+
before_save :cache_attributes
|
|
23
|
+
|
|
24
|
+
# == Search
|
|
25
|
+
plugin Hunt
|
|
26
|
+
searches :reference, :created_by, :stored_variable_input, :stored_identifier, :_extra_keywords
|
|
27
|
+
ensure_index :'searches.default'
|
|
28
|
+
|
|
29
|
+
# == Indexes
|
|
30
|
+
ensure_index :reference
|
|
31
|
+
ensure_index :stored_identifier
|
|
32
|
+
ensure_index :stored_variable_input
|
|
33
|
+
|
|
34
|
+
# == Validations
|
|
35
|
+
validates_presence_of :question_id
|
|
36
|
+
validates_presence_of :answer_params
|
|
37
|
+
validates_presence_of :result
|
|
38
|
+
validates_true_for :answer, :logic => Proc.new {!answer_params.empty?}, :message => nil
|
|
39
|
+
validates_true_for :result, :logic => Proc.new {!result.empty?}, :message => nil
|
|
40
|
+
|
|
41
|
+
# == Associations
|
|
42
|
+
belongs_to :user
|
|
43
|
+
|
|
44
|
+
# == attr Protected
|
|
45
|
+
attr_protected :user_id
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
module ClassMethods
|
|
50
|
+
require "csv" #ruby19
|
|
51
|
+
def self.to_csv(options = {})
|
|
52
|
+
@csv_string ||= FasterCSV.generate do |csv|
|
|
53
|
+
# header row
|
|
54
|
+
csv << self.attributes_for_api
|
|
55
|
+
|
|
56
|
+
# data rows
|
|
57
|
+
self.all(options).each do |resource|
|
|
58
|
+
attributes = self.attributes_for_api.map do |key|
|
|
59
|
+
resource.send(key)
|
|
60
|
+
end
|
|
61
|
+
csv << attributes
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module InstanceMethods
|
|
68
|
+
def add_extra_keywords
|
|
69
|
+
unless (self.class._extra_keyword_methods || []).empty?
|
|
70
|
+
self.class._extra_keyword_methods.each do |method|
|
|
71
|
+
self._extra_keywords << self.send(method)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def object_reference_characteristics(object_reference = self.object_reference)
|
|
77
|
+
object_reference["characteristics"]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def object_references
|
|
81
|
+
result["object_references"]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def object_reference(object_reference_id = self.object_reference_id)
|
|
85
|
+
result["object_references"] && result["object_references"][object_reference_id]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def object_reference_id(object_reference_name = self.object_reference_name)
|
|
89
|
+
answer_params[object_reference_name]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def object_reference_name
|
|
93
|
+
# should be set in the answerable if want to use
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def variable_input
|
|
97
|
+
# should be set in the answerable if you want to use this
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# you should set this to be what stored identifier you
|
|
101
|
+
# wish to have if you use more then 1 object in
|
|
102
|
+
# your calculation
|
|
103
|
+
def _identifier
|
|
104
|
+
idents = []
|
|
105
|
+
object_references.each_pair do |key, value|
|
|
106
|
+
idents << value["identifier"]
|
|
107
|
+
end
|
|
108
|
+
idents.join(" ")
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def identifier
|
|
112
|
+
_identifier == read_attribute(:stored_identifier) ? read_attribute(:stored_identifier) : _identifier
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def co2
|
|
116
|
+
(result["calculations"]["co2"]["value"] || 0).to_f
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def ch4
|
|
120
|
+
(result["calculations"]["ch4"]["value"] || 0).to_f
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def n2o
|
|
124
|
+
(result["calculations"]["n2o"]["value"]|| 0).to_f
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def co2e
|
|
128
|
+
(result["calculations"]["co2e"]["value"] || 0).to_f
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
def add_stored_identifier
|
|
133
|
+
self.stored_identifier = self.identifier
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def cache_attributes
|
|
137
|
+
write_attribute(:created_by, user.full_name)
|
|
138
|
+
write_attribute(:stored_variable_input, variable_input)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
module QuestionChain
|
|
2
|
+
module Answers
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
before_filter :get_context
|
|
7
|
+
before_filter :load_contexts, :except => [:fire_object_search, :fire_populate_drop_down]
|
|
8
|
+
respond_to :json, :only => [:fire_object_search, :fire_populate_drop_down]
|
|
9
|
+
helper_method :question_chain_update_answer_path, :question_chain_answer_path, :collection_path
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module InstanceMethods
|
|
13
|
+
def new
|
|
14
|
+
@answer = build_resource
|
|
15
|
+
enforce_permission
|
|
16
|
+
@question = question_from_context
|
|
17
|
+
new!
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def edit
|
|
21
|
+
@answer = resource
|
|
22
|
+
enforce_permission
|
|
23
|
+
@question = Question.find!(resource.question_id).to_hash
|
|
24
|
+
@answer_params = @answer.answer_params # used for mustache templates
|
|
25
|
+
set_answer_values_on_question!(@question, @answer_params)
|
|
26
|
+
edit!
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update
|
|
30
|
+
@answer = resource
|
|
31
|
+
enforce_permission
|
|
32
|
+
@answer.user_id = current_user.id
|
|
33
|
+
@answer.answer_params = params[:answer]
|
|
34
|
+
@answer_params = params[:answer] # used for mustache templates
|
|
35
|
+
@question = Question.find!(resource.question_id).to_hash
|
|
36
|
+
@answer.result = get_answer(@question, @answer_params)
|
|
37
|
+
set_answer_values_on_question!(@question, @answer_params)
|
|
38
|
+
build_answer_errors!
|
|
39
|
+
update! do |success, failure|
|
|
40
|
+
success.html do
|
|
41
|
+
flash[:notice] = update_success_flash_message
|
|
42
|
+
@contexts << @answer
|
|
43
|
+
redirect_to update_success_path
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def create
|
|
49
|
+
@answer = build_resource
|
|
50
|
+
enforce_permission
|
|
51
|
+
@answer.user_id = current_user.id
|
|
52
|
+
@answer.answer_params = params[:answer]
|
|
53
|
+
@answer_params = params[:answer] # used for mustache templates
|
|
54
|
+
@question = question_from_context
|
|
55
|
+
@answer.question_id = @question.id
|
|
56
|
+
@answer.result = get_answer(@question, @answer_params)
|
|
57
|
+
set_answer_values_on_question!(@question, @answer_params)
|
|
58
|
+
build_answer_errors!
|
|
59
|
+
create! do |success, failure|
|
|
60
|
+
success.html do
|
|
61
|
+
flash[:notice] = create_success_flash_message
|
|
62
|
+
@contexts << @answer
|
|
63
|
+
redirect_to create_success_path
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# == Rule firing for drop down
|
|
69
|
+
def fire_populate_drop_down
|
|
70
|
+
if ui_object = UiObject.find(params[:ui_object_id])
|
|
71
|
+
if rule = ui_object.rules.find(params[:rule_id])
|
|
72
|
+
return render :json => {"options" => rule.get_options(params[:object_ids])}.to_json
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
render :json => {:error => "Could not find rule"}.to_json
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# == Rule firing for search
|
|
79
|
+
def fire_object_search
|
|
80
|
+
if ui_object = UiObject.find(params[:ui_object_id])
|
|
81
|
+
if rule = ui_object.rules.find(params[:rule_id])
|
|
82
|
+
return render :json => {"options" => rule.get_options(params[:q], params[:relatable_category_values])}.to_json
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
render :json => {:error => "Could not find rule"}.to_json
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# seems strange but its true allows
|
|
89
|
+
# for pagination link to work inside list view
|
|
90
|
+
# when editing
|
|
91
|
+
def show
|
|
92
|
+
end_of_association_chain
|
|
93
|
+
redirect_to edit_from_context_path
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# seems strange but its true
|
|
97
|
+
# allows for pagination link to work
|
|
98
|
+
# when creating a new answer
|
|
99
|
+
def index
|
|
100
|
+
end_of_association_chain
|
|
101
|
+
redirect_to new_from_context_path
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def enforce_permission
|
|
105
|
+
# override to force permission on the answer object
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
protected
|
|
109
|
+
def create_success_flash_message
|
|
110
|
+
"Your co2 was #{@answer.result["calculations"]["co2"]["value"]} #{@answer.result["calculations"]["co2"]["units"]}"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def update_success_flash_message
|
|
114
|
+
"Your co2 was updated to #{@answer.result["calculations"]["co2"]["value"]} #{@answer.result["calculations"]["co2"]["units"]}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def question_chain_answer_path
|
|
118
|
+
contexts = @contexts.dup
|
|
119
|
+
contexts << :answers
|
|
120
|
+
self.send(path_method_from_contexts(contexts), {:context => @context, :question_id => @question.id})
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def question_chain_update_answer_path
|
|
124
|
+
contexts = @contexts.dup
|
|
125
|
+
contexts << :answer
|
|
126
|
+
self.send(path_method_from_contexts(contexts), {:context => @context, :question_id => @question.id, :id => resource.id})
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# allows the ui to know what values have been set
|
|
130
|
+
# and therefore sets the ui_objects values
|
|
131
|
+
#
|
|
132
|
+
# @param [Hash] question hash representation of the question
|
|
133
|
+
# @param [Hash] answer_params
|
|
134
|
+
def set_answer_values_on_question!(question_hash, answer)
|
|
135
|
+
answer.each_pair do |key, value|
|
|
136
|
+
question_hash.ui_groups.map{|group| group.ui_objects}.flatten.each do |ui_object|
|
|
137
|
+
if ui_object.name == key.to_s
|
|
138
|
+
ui_object.value = value
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @param [Question] calculator_id
|
|
145
|
+
# @param [Hash] answer_params
|
|
146
|
+
# @return [Hash] the result from the co2 computation
|
|
147
|
+
# which many container errors
|
|
148
|
+
def get_answer(question, answer_params)
|
|
149
|
+
if computation_id = answer_params[:computation_id].blank? ? question.computation_id : answer_params[:computation_id]
|
|
150
|
+
QuestionChain.calculated_session.answer_for_computation(computation_id, answer_params)
|
|
151
|
+
elsif calculator_id = question.calculator_id
|
|
152
|
+
QuestionChain.calculated_session.answer_for_calculator(calculator_id, answer_params)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# we false the generation of any normal errors
|
|
157
|
+
# on the answer and merge in the carboncalculated
|
|
158
|
+
# errors as well
|
|
159
|
+
#
|
|
160
|
+
# base errors are in the form of an array
|
|
161
|
+
# errors that have fields are in the form of a hash
|
|
162
|
+
def build_answer_errors!
|
|
163
|
+
if @answer.result[:errors]
|
|
164
|
+
@answer.valid?
|
|
165
|
+
if @answer.result[:errors].is_a?(Hash)
|
|
166
|
+
@answer.errors.merge!(@answer.result[:errors])
|
|
167
|
+
else
|
|
168
|
+
@answer.errors.merge!({:base => @answer.result[:errors]})
|
|
169
|
+
end
|
|
170
|
+
@answer.errors.each_pair{|key, value| value.respond_to?(:flatten!) ? value.flatten! : value}
|
|
171
|
+
@answer.instance_exec(@answer) do |answer|
|
|
172
|
+
def answer.valid?
|
|
173
|
+
false
|
|
174
|
+
end
|
|
175
|
+
# we dont want this to update any attributes if its invalid!
|
|
176
|
+
# this results in a very strange BUG! if not applied
|
|
177
|
+
def answer.update_attributes(attributes)
|
|
178
|
+
false
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def find_question_ids
|
|
185
|
+
if template = get_chain_template_for_resource(parent_type.to_s)
|
|
186
|
+
template["context"][params[:context]]
|
|
187
|
+
else
|
|
188
|
+
# render not found or something
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def question_from_context
|
|
193
|
+
if question_id = params[:question_id]
|
|
194
|
+
Question.find!(question_id).to_hash
|
|
195
|
+
else
|
|
196
|
+
ids = find_question_ids
|
|
197
|
+
Question.find!(ids.first).to_hash
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def resource_collection_name
|
|
202
|
+
@context
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# handle single resource case scenerio via singularize
|
|
206
|
+
def resource
|
|
207
|
+
if resource_collection_name.singularize == resource_collection_name
|
|
208
|
+
get_resource_ivar || set_resource_ivar(end_of_association_chain)
|
|
209
|
+
else
|
|
210
|
+
get_resource_ivar || set_resource_ivar(end_of_association_chain.find(params[:id]))
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def collection
|
|
215
|
+
get_collection_ivar || set_collection_ivar(end_of_association_chain.paginate(:page => params[:page], :per_page => 25, :order => :created_at.desc))
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def get_context
|
|
219
|
+
@context = params[:context]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Loads the contexts and any parent resources
|
|
223
|
+
# to allow easy generation of urls back to
|
|
224
|
+
# the context enclosing resources
|
|
225
|
+
def load_contexts(enclosed_parent = nil)
|
|
226
|
+
end_of_association_chain
|
|
227
|
+
@contexts = [] if @contexts.nil?
|
|
228
|
+
enclosed_parent = enclosed_parent.nil? ? self.parent : enclosed_parent
|
|
229
|
+
unless @contexts.include?(enclosed_parent)
|
|
230
|
+
@contexts << enclosed_parent
|
|
231
|
+
if chain_template = get_chain_template_for_resource(parent.class.name.downcase)
|
|
232
|
+
if parent_resource = chain_template.parent_resource
|
|
233
|
+
resource = parent.send(parent_resource)
|
|
234
|
+
instance_variable_set("@#{parent_resource}", resource)
|
|
235
|
+
load_contexts(resource)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
@contexts.reverse!
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def new_from_context_path
|
|
243
|
+
new_polymorphic_path(@contexts)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def edit_from_context_path
|
|
247
|
+
new_polymorphic_path(@contexts)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# if a method matching the context and action that will be called
|
|
251
|
+
# otherwise the polymorphic path is used
|
|
252
|
+
def create_success_path
|
|
253
|
+
if self.respond_to?(path_method_from_contexts(@contexts, "create_success_"))
|
|
254
|
+
self.send(path_method_from_contexts(@contexts, "create_success_"))
|
|
255
|
+
else
|
|
256
|
+
polymorphic_path(@contexts)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# builds a url method from the contexts and a given action
|
|
261
|
+
# @param [String] action
|
|
262
|
+
#
|
|
263
|
+
# @return [String] url method call
|
|
264
|
+
def path_method_from_contexts(contexts, action = "")
|
|
265
|
+
url_method = contexts.inject("#{action}") do |string, parent|
|
|
266
|
+
segment = (parent.is_a?(Symbol)) ? parent.to_s : ActiveModel::Naming.singular(parent)
|
|
267
|
+
string << segment
|
|
268
|
+
string << "_"
|
|
269
|
+
end
|
|
270
|
+
url_method << "path"
|
|
271
|
+
url_method
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# if a method has been decleared of a specific update that is called
|
|
275
|
+
# otherwise the default polymophic path is used
|
|
276
|
+
def update_success_path
|
|
277
|
+
if self.respond_to?(path_method_from_contexts(@contexts, "update_success_"))
|
|
278
|
+
self.send(path_method_from_contexts(@contexts, "update_success_"))
|
|
279
|
+
else
|
|
280
|
+
polymorphic_path(@contexts)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def get_chain_template_for_resource(for_resource)
|
|
285
|
+
ChainTemplate.first(:model_state => "active", :for_resource => for_resource, :account_id => @account.try(:id)) ||
|
|
286
|
+
ChainTemplate.first(:model_state => "active", :for_resource => for_resource)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Answers
|
|
2
|
+
class QuestionView < MustacheRails
|
|
3
|
+
|
|
4
|
+
def name
|
|
5
|
+
question.name
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def label
|
|
9
|
+
question.label
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def description
|
|
13
|
+
question.description
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
def question
|
|
18
|
+
@question ||= context[:_question]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Answers
|
|
2
|
+
class UiObjectView < MustacheRails
|
|
3
|
+
|
|
4
|
+
def dom_id
|
|
5
|
+
"ui_object_#{ui_object.id}"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def input_id
|
|
9
|
+
"ui_input_#{ui_object.id}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def extra_info
|
|
13
|
+
ui_object.try(:extra_info)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def css_classes
|
|
17
|
+
ui_object.css_classes.join(" ")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def has_extra_info
|
|
21
|
+
!extra_info.blank?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def label
|
|
25
|
+
ui_object.label
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def value
|
|
29
|
+
answer_params[ui_object_name] if answer_params
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ui_object_name
|
|
33
|
+
ui_object.name
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def name
|
|
37
|
+
"answer[#{ui_object.name}]"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def default_value
|
|
41
|
+
ui_object.default_value
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def default_styles
|
|
45
|
+
default_styles = ""
|
|
46
|
+
ui_object.ui_attributes.each_pair do |key, value|
|
|
47
|
+
if key.to_s == "visible" && value == "false"
|
|
48
|
+
default_styles << "display:none;visibility:hidden;"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
default_styles
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def disabled
|
|
55
|
+
ui_object.ui_attributes["disable"] == "true"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
protected
|
|
59
|
+
def ui_object
|
|
60
|
+
@ui_object ||= context[:_ui_object]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def answer_params
|
|
64
|
+
@answer_params ||= context[:_answer_params]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Answers
|
|
2
|
+
class UiObjectsDropDownView < Answers::UiObjectView
|
|
3
|
+
|
|
4
|
+
def prompt
|
|
5
|
+
ui_object.prompt
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def options
|
|
9
|
+
if answer_params
|
|
10
|
+
ui_object.options.map{|option| option.merge!(:selected => option["value"].to_s == value.to_s)}
|
|
11
|
+
else
|
|
12
|
+
ui_object.options
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Answers
|
|
2
|
+
class UiObjectsObjectReferenceDropDownView < Answers::UiObjectView
|
|
3
|
+
|
|
4
|
+
def prompt
|
|
5
|
+
ui_object.prompt
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# @return [Array<Hash<value => value, name => name>>]
|
|
9
|
+
def options
|
|
10
|
+
if answer_params
|
|
11
|
+
ui_object.options.map{|option| option.merge!(:selected => option["value"].to_s == value.to_s)}
|
|
12
|
+
else
|
|
13
|
+
ui_object.options
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Answers
|
|
2
|
+
class UiObjectsObjectSearchView < Answers::UiObjectView
|
|
3
|
+
|
|
4
|
+
def search_name
|
|
5
|
+
"answer[search_#{name}]"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def search_id
|
|
9
|
+
"search_#{dom_id()}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def search_value
|
|
13
|
+
if answer_params
|
|
14
|
+
answer_params["search_answer"][ui_object_name]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def value
|
|
19
|
+
super || default_value
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|