qwester 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +51 -0
- data/app/controllers/qwester/application_controller.rb +1 -2
- data/app/controllers/qwester/questionnaires_controller.rb +1 -2
- data/app/models/qwester/presentation.rb +45 -0
- data/app/models/qwester/presentation_questionnaire.rb +8 -0
- data/app/models/qwester/questionnaire.rb +7 -0
- data/app/models/qwester/rule_set.rb +2 -2
- data/app/views/qwester/questionnaires/index.html.erb +3 -3
- data/db/migrate/20130315112847_create_qwester_presentations.rb +11 -0
- data/db/migrate/20130315113027_create_qwester_presentation_questionnaires.rb +10 -0
- data/db/migrate/20130318102537_add_presentation_to_rule_sets.rb +6 -0
- data/lib/active_admin/admin/answers.rb +1 -1
- data/lib/active_admin/admin/presentations.rb +51 -0
- data/lib/active_admin/admin/questionnaires.rb +2 -0
- data/lib/active_admin/admin/questions.rb +2 -0
- data/lib/active_admin/admin/rule_sets.rb +35 -0
- data/lib/qwester/version.rb +7 -1
- data/lib/rails/actionpack/lib/action_controller/base.rb +36 -3
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20130315113346_create_qwester_presentations.qwester.rb +12 -0
- data/test/dummy/db/migrate/20130315113347_create_qwester_presentation_questionnaires.qwester.rb +11 -0
- data/test/dummy/db/migrate/20130318123540_add_presentation_to_rule_sets.qwester.rb +7 -0
- data/test/dummy/db/schema.rb +20 -3
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +9021 -0
- data/test/dummy/log/test.log +146429 -0
- data/test/dummy/public/system/qwester/questionnaires/button_images/000/000/001/link/commend_button.png +0 -0
- data/test/dummy/public/system/qwester/questionnaires/button_images/000/000/001/original/commend_button.png +0 -0
- data/test/dummy/public/system/qwester/questionnaires/button_images/000/000/001/thumbnail/commend_button.png +0 -0
- data/test/dummy/public/system/qwester/questionnaires/button_images/000/000/002/link/commend_button.gif +0 -0
- data/test/dummy/public/system/qwester/questionnaires/button_images/000/000/002/original/commend_button.gif +0 -0
- data/test/dummy/public/system/qwester/questionnaires/button_images/000/000/002/thumbnail/commend_button.gif +0 -0
- data/test/dummy/test/fixtures/qwester/presentation_questionnaires.yml +3 -0
- data/test/dummy/test/fixtures/qwester/presentations.yml +13 -0
- data/test/dummy/test/functional/qwester/questionnaires_controller_test.rb +68 -3
- data/test/unit/qwester/presentation_test.rb +61 -0
- data/test/unit/qwester/questionnaire_test.rb +5 -1
- data/test/unit/qwester/rule_set_test.rb +12 -0
- metadata +32 -2
data/README.rdoc
CHANGED
@@ -133,6 +133,57 @@ to a resource either within or outside the app.
|
|
133
133
|
RuleSet uses array_logic[http://github.com/reggieb/array_logic] to manage
|
134
134
|
the logic used to compare each rule set with the array of answers.
|
135
135
|
|
136
|
+
== Presentation
|
137
|
+
|
138
|
+
Questionnaires can be grouped into Presentations, and these are used to
|
139
|
+
control which questionnaires are displayed (presented to the user) at
|
140
|
+
any time.
|
141
|
+
|
142
|
+
All questionnaires are display at the engine root unless:
|
143
|
+
|
144
|
+
* A presentation is set as 'default'
|
145
|
+
|
146
|
+
* An existing presentation's name is added to session[:presentations]
|
147
|
+
(an array)
|
148
|
+
|
149
|
+
=== Restricting the questionnaires displayed
|
150
|
+
|
151
|
+
If you do not want to display all the available questionnaires, create
|
152
|
+
a presentation, set it as 'default' and add to it the questionnaires you
|
153
|
+
wish to display.
|
154
|
+
|
155
|
+
=== Using a questionnaire to control access to other questionnaires
|
156
|
+
|
157
|
+
Say you have three presentations of questionnaires, and you want to display
|
158
|
+
one initially. Then you want to use the answers submitted from that
|
159
|
+
questionnaire, to control which of the other two sets of questionnaires are
|
160
|
+
displayed next.
|
161
|
+
|
162
|
+
To do this set the initial presentation as default. Then create two rule
|
163
|
+
sets, one for each of the other presentations. Update each rule set to
|
164
|
+
match the answer pattern that should be submitted for the associated
|
165
|
+
pattern to be displayed, and set rule_set#presentation to the name of
|
166
|
+
the presentation you wish displayed when the rule is matched.
|
167
|
+
|
168
|
+
Then when the first set of questionnaires are submitted, the rules will be
|
169
|
+
checked, and if one of the two rules sets matches the submitted answers,
|
170
|
+
the associated presentation's questionnaires will be displayed.
|
171
|
+
|
172
|
+
=== Simple rule matching for presentations
|
173
|
+
|
174
|
+
The rule matching is simple and if two presentation rules match, the system
|
175
|
+
will not try to work out which one it should display. It will just show the
|
176
|
+
last one it finds. So some care is required when setting up presentations
|
177
|
+
with matching rule sets to avoid overlaps and clashes.
|
178
|
+
|
179
|
+
=== Once only match
|
180
|
+
|
181
|
+
Once a presentation has been matched, it cannot be returned to later. That
|
182
|
+
is if there are two presentations: 'one' and 'two', you cannot have a work
|
183
|
+
flow that goes from one to two and then back to one, unless you reset or
|
184
|
+
otherwise manipulate session[:presentations]. Instead you should clone 'one'
|
185
|
+
as a new presentation e.g. 'three', and then go from one to two to three.
|
186
|
+
|
136
187
|
== Dummy
|
137
188
|
|
138
189
|
A test app is present within this engine, and provides an example of how
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Qwester
|
2
|
+
class Presentation < ActiveRecord::Base
|
3
|
+
attr_accessible :description, :name, :title, :questionnaire_ids, :default
|
4
|
+
|
5
|
+
has_many :presentation_questionnaires
|
6
|
+
|
7
|
+
has_many(
|
8
|
+
:questionnaires,
|
9
|
+
:through => :presentation_questionnaires
|
10
|
+
)
|
11
|
+
accepts_nested_attributes_for :questionnaires
|
12
|
+
|
13
|
+
before_save :before_save_tasks
|
14
|
+
after_save :after_save_tasks
|
15
|
+
|
16
|
+
validates(
|
17
|
+
:name,
|
18
|
+
:format => {
|
19
|
+
:with => /^\w+$/,
|
20
|
+
:message => "must comprise letters or numbers with underscores separating words"
|
21
|
+
},
|
22
|
+
:presence => true,
|
23
|
+
:uniqueness => true
|
24
|
+
)
|
25
|
+
|
26
|
+
private
|
27
|
+
def before_save_tasks
|
28
|
+
update_title_from_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def after_save_tasks
|
32
|
+
undefault_others if self.default?
|
33
|
+
end
|
34
|
+
|
35
|
+
def undefault_others
|
36
|
+
current_defaults = self.class.find_all_by_default(true)
|
37
|
+
current_defaults.each{|p| p.update_attribute(:default, false) unless p == self}
|
38
|
+
end
|
39
|
+
|
40
|
+
def update_title_from_name
|
41
|
+
self.title = self.name.humanize unless self.title.present?
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -34,6 +34,13 @@ module Qwester
|
|
34
34
|
:join_table => :qwester_answer_stores_questionnaires,
|
35
35
|
:uniq => true
|
36
36
|
)
|
37
|
+
|
38
|
+
has_many :presentation_questionnaires
|
39
|
+
|
40
|
+
has_many(
|
41
|
+
:presentations,
|
42
|
+
:through => :presentation_questionnaires
|
43
|
+
)
|
37
44
|
|
38
45
|
validates :title, :presence => true
|
39
46
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'array_logic'
|
2
2
|
module Qwester
|
3
3
|
class RuleSet < ActiveRecord::Base
|
4
|
-
attr_accessible :title, :description, :answers, :url, :rule, :answer_ids, :link_text, :warning_id
|
4
|
+
attr_accessible :title, :description, :answers, :url, :rule, :answer_ids, :link_text, :warning_id, :presentation
|
5
5
|
|
6
6
|
before_save :keep_answers_in_step_with_rule
|
7
7
|
|
@@ -23,7 +23,7 @@ module Qwester
|
|
23
23
|
validate :check_rule_is_valid
|
24
24
|
|
25
25
|
validates :title, :presence => true
|
26
|
-
validates :url, :presence =>
|
26
|
+
validates :url, :presence => {:unless => :presentation?}
|
27
27
|
|
28
28
|
|
29
29
|
def self.matching(answers)
|
@@ -19,10 +19,10 @@
|
|
19
19
|
<% end %>
|
20
20
|
</div>
|
21
21
|
|
22
|
-
<% if @
|
22
|
+
<% if @qwester_rule_sets.present? %>
|
23
23
|
<h2>Matching rule sets</h2>
|
24
24
|
<ul>
|
25
|
-
<% @
|
25
|
+
<% @qwester_rule_sets.each do |rule_set| %>
|
26
26
|
<li>
|
27
27
|
<%= rule_set.title %>:
|
28
28
|
<%= link_to(rule_set.link_text, rule_set.url) %>
|
@@ -35,5 +35,5 @@
|
|
35
35
|
content_tag(
|
36
36
|
'p',
|
37
37
|
link_to('Clear answers and start again', reset_questionnaires_path)
|
38
|
-
) if @
|
38
|
+
) if @qwester_rule_sets.present?
|
39
39
|
%>
|
@@ -7,6 +7,7 @@ module Qwester
|
|
7
7
|
menu :parent => Qwester.active_admin_menu, :label => menu_label
|
8
8
|
|
9
9
|
actions :all, :except => [:edit]
|
10
|
+
config.batch_actions = false
|
10
11
|
|
11
12
|
index do
|
12
13
|
column :id
|
@@ -15,7 +16,6 @@ module Qwester
|
|
15
16
|
link_to(answer.question.title, edit_admin_qwester_question_path(answer.question)) if answer.question
|
16
17
|
end
|
17
18
|
column :position
|
18
|
-
column :cope_index
|
19
19
|
default_actions
|
20
20
|
end
|
21
21
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Qwester
|
2
|
+
ActiveAdmin.register Presentation do
|
3
|
+
|
4
|
+
menu_label = 'Presentations'
|
5
|
+
menu_label = "Qwester #{menu_label}" unless Qwester.active_admin_menu
|
6
|
+
menu :parent => Qwester.active_admin_menu, :label => menu_label
|
7
|
+
|
8
|
+
config.batch_actions = false
|
9
|
+
|
10
|
+
index do
|
11
|
+
column :name do |presentation|
|
12
|
+
link_to presentation.name, admin_qwester_presentation_path(presentation)
|
13
|
+
end
|
14
|
+
column :title
|
15
|
+
column :default do |presentation|
|
16
|
+
'default' if presentation.default?
|
17
|
+
end
|
18
|
+
column :questionnaires do |presentation|
|
19
|
+
presentation.questionnaires.collect(&:title).join(', ')
|
20
|
+
end
|
21
|
+
default_actions
|
22
|
+
end
|
23
|
+
|
24
|
+
show do
|
25
|
+
h2 qwester_presentation.title
|
26
|
+
qwester_presentation.questionnaires.each do |questionnaire|
|
27
|
+
div(:style => 'display:inline-block;margin-right:20px;') do
|
28
|
+
para image_tag(questionnaire.button_image.url(:thumbnail))
|
29
|
+
para questionnaire.title
|
30
|
+
end
|
31
|
+
end
|
32
|
+
para "Default: Will be inital presentation of quesitonnaires" if qwester_presentation.default?
|
33
|
+
end
|
34
|
+
|
35
|
+
form do |f|
|
36
|
+
f.inputs "Details" do
|
37
|
+
f.input :name
|
38
|
+
f.input :title, :label => "Title (or create from name)"
|
39
|
+
f.input :default, :label => 'Set as default (that is, the first presentation displayed to a user). If no default, all questionnaires will be displayed'
|
40
|
+
if defined?(Ckeditor)
|
41
|
+
f.input :description, :as => :ckeditor, :input_html => { :height => 100, :toolbar => 'Basic' }
|
42
|
+
else
|
43
|
+
f.input :description, :input_html => { :rows => 3}
|
44
|
+
end
|
45
|
+
f.input :questionnaires, :as => :check_boxes, :collection => Questionnaire.all
|
46
|
+
end
|
47
|
+
f.buttons
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -6,6 +6,8 @@ module Qwester
|
|
6
6
|
menu_label = "Qwester #{menu_label}" unless Qwester.active_admin_menu
|
7
7
|
menu :parent => Qwester.active_admin_menu, :label => menu_label
|
8
8
|
|
9
|
+
config.batch_actions = false
|
10
|
+
|
9
11
|
index do
|
10
12
|
column :image do |questionnaire|
|
11
13
|
image_tag(questionnaire.button_image.url(:thumbnail))
|
@@ -6,8 +6,11 @@ module Qwester
|
|
6
6
|
menu_label = "Qwester #{menu_label}" unless Qwester.active_admin_menu
|
7
7
|
menu :parent => Qwester.active_admin_menu, :label => menu_label
|
8
8
|
|
9
|
+
config.batch_actions = false
|
10
|
+
|
9
11
|
index do
|
10
12
|
column :title
|
13
|
+
column :presentation
|
11
14
|
column :answers do |rule_set|
|
12
15
|
rule_set.answers.count
|
13
16
|
end
|
@@ -57,6 +60,25 @@ module Qwester
|
|
57
60
|
|
58
61
|
end
|
59
62
|
|
63
|
+
sidebar :presentations do
|
64
|
+
para <<EOF
|
65
|
+
If a rule is assigned a presentation, that presentation's questionnaires will
|
66
|
+
be displayed when the rule is matched.
|
67
|
+
EOF
|
68
|
+
|
69
|
+
para <<EOF
|
70
|
+
There is no mechanism to handle multiple rules with presentations, being trigged
|
71
|
+
at the same time. The app will just display the questionnaires assigned to the
|
72
|
+
last rule_set.presentation it finds. So some care should be taken to avoid
|
73
|
+
clashes.
|
74
|
+
EOF
|
75
|
+
|
76
|
+
para <<EOF
|
77
|
+
A rule set with a presentation, will change the display. It will not display
|
78
|
+
an output tab, any url associated with the rule will be ignored.
|
79
|
+
EOF
|
80
|
+
end
|
81
|
+
|
60
82
|
form do |f|
|
61
83
|
f.inputs "Details" do
|
62
84
|
f.input :title
|
@@ -72,6 +94,10 @@ module Qwester
|
|
72
94
|
f.input :link_text
|
73
95
|
end
|
74
96
|
|
97
|
+
f.inputs "Change Presentation of Questionnaires" do
|
98
|
+
f.input :presentation, :as => :select, :collection => Presentation.all.collect(&:name), :include_blank => 'No effect on presentation'
|
99
|
+
end
|
100
|
+
|
75
101
|
f.inputs "Logic" do
|
76
102
|
f.input :rule, :input_html => { :rows => 3}
|
77
103
|
end
|
@@ -123,6 +149,15 @@ module Qwester
|
|
123
149
|
para qwester_rule_set.link_text? ? qwester_rule_set.link_text : 'No link text specified'
|
124
150
|
end
|
125
151
|
|
152
|
+
div do
|
153
|
+
h3 'Presentation'
|
154
|
+
if qwester_rule_set.presentation?
|
155
|
+
para "The presentations of questionnaires should change to: #{qwester_rule_set.presentation}"
|
156
|
+
else
|
157
|
+
para "The presentations of questionnaires should be unaffected by this rule"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
126
161
|
div do
|
127
162
|
h3 'The rule'
|
128
163
|
para qwester_rule_set.rule
|
data/lib/qwester/version.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
module Qwester
|
2
|
-
VERSION = "0.0
|
2
|
+
VERSION = "0.1.0"
|
3
3
|
end
|
4
4
|
|
5
5
|
# History
|
6
6
|
# =======
|
7
7
|
#
|
8
|
+
# 0.1.0 - Add presentations as a way of controlling the display of questionnaires
|
9
|
+
# Allows admin to define groups of questionnaires as presentation views
|
10
|
+
# and rule sets that will display a presentation when triggered. In that way
|
11
|
+
# the list of questionnaires being displayed can change as questionnaires are
|
12
|
+
# submitted.
|
13
|
+
#
|
8
14
|
# 0.0.9 - maintenance update
|
9
15
|
# Removes cope_index from migrations.
|
10
16
|
# Ensures answer_store#session_id is unique
|
@@ -33,13 +33,46 @@ module ActionController
|
|
33
33
|
@qwester_answer_store
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
36
|
+
def match_rule_sets
|
37
37
|
if get_qwester_answer_store
|
38
|
-
Qwester::RuleSet.matching(@qwester_answer_store.answers)
|
38
|
+
@qwester_rule_sets = Qwester::RuleSet.matching(@qwester_answer_store.answers)
|
39
|
+
get_presentation_from_rule_sets
|
40
|
+
return @qwester_rule_sets
|
41
|
+
end
|
42
|
+
end
|
43
|
+
alias_method :matching_rule_sets, :match_rule_sets
|
44
|
+
|
45
|
+
def current_questionnaires
|
46
|
+
match_rule_sets
|
47
|
+
presentation_questionnaires || default_presentation_questionnaires || Qwester::Questionnaire.all
|
48
|
+
end
|
49
|
+
|
50
|
+
def presentation_questionnaires
|
51
|
+
presentation = Qwester::Presentation.find_by_name(session[:presentations].last) if session[:presentations]
|
52
|
+
presentation.questionnaires if presentation
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_presentation_questionnaires
|
56
|
+
presentation = Qwester::Presentation.find_by_default(true)
|
57
|
+
presentation.questionnaires if presentation
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_presentation_from_rule_sets
|
61
|
+
@qwester_rule_sets.clone.each do |rule_set|
|
62
|
+
next unless rule_set.presentation?
|
63
|
+
add_presentation_to_session rule_set.presentation
|
64
|
+
@qwester_rule_sets.delete(rule_set)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_presentation_to_session(presentation)
|
69
|
+
session_presentations = session[:presentations] || []
|
70
|
+
unless session_presentations.include? presentation
|
71
|
+
session_presentations << presentation
|
72
|
+
session[:presentations] = session_presentations
|
39
73
|
end
|
40
74
|
end
|
41
75
|
|
42
|
-
# private
|
43
76
|
def add_answers_to_qwester_answer_store
|
44
77
|
answers = params[:question_id].values.collect do |question_values|
|
45
78
|
question_values[:answer_ids].collect{|id| Qwester::Answer.find(id)}
|
Binary file
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# This migration comes from qwester (originally 20130315112847)
|
2
|
+
class CreateQwesterPresentations < ActiveRecord::Migration
|
3
|
+
def change
|
4
|
+
create_table :qwester_presentations do |t|
|
5
|
+
t.string :name
|
6
|
+
t.string :title
|
7
|
+
t.text :description
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/test/dummy/db/migrate/20130315113347_create_qwester_presentation_questionnaires.qwester.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# This migration comes from qwester (originally 20130315113027)
|
2
|
+
class CreateQwesterPresentationQuestionnaires < ActiveRecord::Migration
|
3
|
+
def change
|
4
|
+
create_table :qwester_presentation_questionnaires do |t|
|
5
|
+
t.integer :questionnaire_id
|
6
|
+
t.integer :presentation_id
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/test/dummy/db/schema.rb
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended to check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(:version =>
|
14
|
+
ActiveRecord::Schema.define(:version => 20130318123540) do
|
15
15
|
|
16
16
|
create_table "active_admin_comments", :force => true do |t|
|
17
17
|
t.string "resource_id", :null => false
|
@@ -91,6 +91,22 @@ ActiveRecord::Schema.define(:version => 20130314103662) do
|
|
91
91
|
add_index "qwester_ckeditor_assets", ["assetable_type", "assetable_id"], :name => "qwester_idx_ckeditor_assetable"
|
92
92
|
add_index "qwester_ckeditor_assets", ["assetable_type", "type", "assetable_id"], :name => "qwester_idx_ckeditor_assetable_type"
|
93
93
|
|
94
|
+
create_table "qwester_presentation_questionnaires", :force => true do |t|
|
95
|
+
t.integer "questionnaire_id"
|
96
|
+
t.integer "presentation_id"
|
97
|
+
t.datetime "created_at", :null => false
|
98
|
+
t.datetime "updated_at", :null => false
|
99
|
+
end
|
100
|
+
|
101
|
+
create_table "qwester_presentations", :force => true do |t|
|
102
|
+
t.string "name"
|
103
|
+
t.string "title"
|
104
|
+
t.text "description"
|
105
|
+
t.datetime "created_at", :null => false
|
106
|
+
t.datetime "updated_at", :null => false
|
107
|
+
t.boolean "default"
|
108
|
+
end
|
109
|
+
|
94
110
|
create_table "qwester_questionnaires", :force => true do |t|
|
95
111
|
t.string "title"
|
96
112
|
t.text "description"
|
@@ -127,10 +143,11 @@ ActiveRecord::Schema.define(:version => 20130314103662) do
|
|
127
143
|
t.string "title"
|
128
144
|
t.text "description"
|
129
145
|
t.string "url"
|
130
|
-
t.datetime "created_at",
|
131
|
-
t.datetime "updated_at",
|
146
|
+
t.datetime "created_at", :null => false
|
147
|
+
t.datetime "updated_at", :null => false
|
132
148
|
t.text "rule"
|
133
149
|
t.string "link_text"
|
150
|
+
t.string "presentation"
|
134
151
|
end
|
135
152
|
|
136
153
|
end
|
data/test/dummy/db/test.sqlite3
CHANGED
Binary file
|