surveyor 0.6.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 +6 -0
- data/MIT-LICENSE +20 -0
- data/README.md +104 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/app/controllers/surveyor_controller.rb +117 -0
- data/app/helpers/survey_form_builder.rb +37 -0
- data/app/helpers/surveyor_helper.rb +66 -0
- data/app/models/answer.rb +21 -0
- data/app/models/dependency.rb +46 -0
- data/app/models/dependency_condition.rb +79 -0
- data/app/models/question.rb +54 -0
- data/app/models/question_group.rb +18 -0
- data/app/models/response.rb +47 -0
- data/app/models/response_set.rb +185 -0
- data/app/models/survey.rb +57 -0
- data/app/models/survey_section.rb +15 -0
- data/app/views/layouts/surveyor_default.html.erb +13 -0
- data/app/views/partials/_answer.html.haml +49 -0
- data/app/views/partials/_question.html.haml +73 -0
- data/app/views/partials/_question_group.html.haml +41 -0
- data/app/views/surveyor/edit.html.haml +32 -0
- data/app/views/surveyor/new.html.haml +17 -0
- data/app/views/surveyor/show.html.haml +12 -0
- data/config/routes.rb +10 -0
- data/generators/surveyor/EXTENDING_SURVEYOR +12 -0
- data/generators/surveyor/extend_surveyor_generator.rb +22 -0
- data/generators/surveyor/surveyor_generator.rb +60 -0
- data/generators/surveyor/templates/README +10 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_leftright.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_updown.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_close.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_doc.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_closed.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_open.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_minus.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_plus.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_11x11_icon_resize_se.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_35x9_colorpicker_indicator.gif.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_down.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_left.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_right.gif +0 -0
- data/generators/surveyor/templates/assets/images/222222_7x7_arrow_up.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_leftright.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_updown.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_close.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_doc.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_closed.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_open.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_minus.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_11x11_icon_plus.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_down.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_left.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_right.gif +0 -0
- data/generators/surveyor/templates/assets/images/454545_7x7_arrow_up.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_leftright.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_updown.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_close.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_doc.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_closed.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_open.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_minus.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_11x11_icon_plus.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_down.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_left.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_right.gif +0 -0
- data/generators/surveyor/templates/assets/images/888888_7x7_arrow_up.gif +0 -0
- data/generators/surveyor/templates/assets/images/dadada_40x100_textures_02_glass_75.png +0 -0
- data/generators/surveyor/templates/assets/images/e6e6e6_40x100_textures_02_glass_75.png +0 -0
- data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_01_flat_0.png +0 -0
- data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_02_glass_65.png +0 -0
- data/generators/surveyor/templates/assets/javascripts/accessibleUISlider.jQuery.js +201 -0
- data/generators/surveyor/templates/assets/javascripts/jquery-1.2.6.js +3549 -0
- data/generators/surveyor/templates/assets/javascripts/jquery-ui-personalized-1.5.3.js +7616 -0
- data/generators/surveyor/templates/assets/javascripts/jquery.form.js +637 -0
- data/generators/surveyor/templates/assets/javascripts/surveyor.js +28 -0
- data/generators/surveyor/templates/assets/stylesheets/jquery-ui-slider-additions.css +71 -0
- data/generators/surveyor/templates/assets/stylesheets/reset.css +46 -0
- data/generators/surveyor/templates/assets/stylesheets/sass/surveyor.sass +245 -0
- data/generators/surveyor/templates/assets/stylesheets/surveyor.css +231 -0
- data/generators/surveyor/templates/assets/stylesheets/ui.theme.css +851 -0
- data/generators/surveyor/templates/extensions/survey_extensions.rb +18 -0
- data/generators/surveyor/templates/extensions/surveyor_controller_extensions.rb +28 -0
- data/generators/surveyor/templates/extensions/surveyor_custom.html.erb +13 -0
- data/generators/surveyor/templates/extensions/surveyor_helper_extensions.rb +18 -0
- data/generators/surveyor/templates/initializers/haml.rb +8 -0
- data/generators/surveyor/templates/initializers/surveyor.rb +11 -0
- data/generators/surveyor/templates/migrate/create_answers.rb +45 -0
- data/generators/surveyor/templates/migrate/create_dependencies.rb +21 -0
- data/generators/surveyor/templates/migrate/create_dependency_conditions.rb +29 -0
- data/generators/surveyor/templates/migrate/create_question_groups.rb +18 -0
- data/generators/surveyor/templates/migrate/create_questions.rb +33 -0
- data/generators/surveyor/templates/migrate/create_response_sets.rb +22 -0
- data/generators/surveyor/templates/migrate/create_responses.rb +33 -0
- data/generators/surveyor/templates/migrate/create_survey_sections.rb +25 -0
- data/generators/surveyor/templates/migrate/create_surveys.rb +25 -0
- data/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +201 -0
- data/generators/surveyor/templates/tasks/surveyor.rb +4 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/lib/surveyor.rb +7 -0
- data/lib/surveyor/config.rb +45 -0
- data/lib/tasks/surveyor_tasks.rake +33 -0
- data/lib/tiny_code.rb +58 -0
- data/lib/xml_formatter.rb +12 -0
- data/script/surveyor/answer.rb +84 -0
- data/script/surveyor/columnizer.rb +36 -0
- data/script/surveyor/dependency.rb +43 -0
- data/script/surveyor/dependency_condition.rb +74 -0
- data/script/surveyor/question.rb +76 -0
- data/script/surveyor/question_group.rb +33 -0
- data/script/surveyor/specs/answer_spec.rb +66 -0
- data/script/surveyor/specs/question_dependency_spec.rb +46 -0
- data/script/surveyor/specs/question_group_spec.rb +9 -0
- data/script/surveyor/specs/question_spec.rb +111 -0
- data/script/surveyor/specs/section_spec.rb +58 -0
- data/script/surveyor/survey.rb +108 -0
- data/script/surveyor/survey_parser.rb +64 -0
- data/script/surveyor/survey_section.rb +153 -0
- data/script/surveyor/whr_dsl.tmproj +244 -0
- data/spec/controllers/surveyor_controller_spec.rb +328 -0
- data/spec/factories.rb +107 -0
- data/spec/models/answer_spec.rb +29 -0
- data/spec/models/dependency_condition_spec.rb +338 -0
- data/spec/models/dependency_spec.rb +82 -0
- data/spec/models/question_group_spec.rb +11 -0
- data/spec/models/question_spec.rb +75 -0
- data/spec/models/response_set_spec.rb +153 -0
- data/spec/models/response_spec.rb +94 -0
- data/spec/models/survey_section_spec.rb +34 -0
- data/spec/models/survey_spec.rb +72 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +14 -0
- data/surveyor.gemspec +187 -0
- data/uninstall.rb +1 -0
- metadata +211 -0
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2008-2009 Brian Chamberlain and Mark Yoon
|
|
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.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Survey On Rails
|
|
2
|
+
|
|
3
|
+
Surveyor is a rails (gem) plugin, that brings surveys to your rails app. Before Rails 2.3, it was implemented as a Rails Engine. Surveys are written in a DSL (Domain Specific Language), with examples available in the "kitchen sink" survey.
|
|
4
|
+
|
|
5
|
+
# Installation
|
|
6
|
+
|
|
7
|
+
As a plugin:
|
|
8
|
+
|
|
9
|
+
sudo gem install haml
|
|
10
|
+
script/plugin install git://github.com/breakpointer/surveyor.git
|
|
11
|
+
|
|
12
|
+
Or as a gem plugin:
|
|
13
|
+
|
|
14
|
+
# in environment.rb
|
|
15
|
+
config.gem "surveyor", :version => '>=0.4.1', :lib => false
|
|
16
|
+
|
|
17
|
+
sudo rake gems:install
|
|
18
|
+
|
|
19
|
+
Generate assets, run migrations:
|
|
20
|
+
|
|
21
|
+
script/generate surveyor
|
|
22
|
+
rake db:migrate
|
|
23
|
+
|
|
24
|
+
Try out the "kitchen sink" survey:
|
|
25
|
+
|
|
26
|
+
rake surveyor FILE=surveys/kitchen_sink_survey.rb
|
|
27
|
+
|
|
28
|
+
# Configuration
|
|
29
|
+
|
|
30
|
+
The surveyor generator creates config/initializers/surveyor.rb. There, you can specify:
|
|
31
|
+
|
|
32
|
+
- your own relative root for surveys ('/' is not recommended as any path will be interpreted as a survey name)
|
|
33
|
+
- your own custom title (string) for the survey list page
|
|
34
|
+
- your own custom layout file name, in your app/views/layouts folder
|
|
35
|
+
- your own custom finish url for all surveys. you can give a string (a path), a symbol (the name of a method in ApplicationController)
|
|
36
|
+
- if you would like surveys to require authorization via the restful_authentication plugin
|
|
37
|
+
- if you would like to extend the surveyor_controller (see Extending Surveyor below)
|
|
38
|
+
|
|
39
|
+
The initializer runs once, when the app starts. The block style is used to keep multiple options DRY (defaults below):
|
|
40
|
+
|
|
41
|
+
Surveyor::Config.run do |config|
|
|
42
|
+
config['default.relative_url_root'] = "surveys/" # should end with '/'
|
|
43
|
+
config['default.title'] = "You can take these surveys:"
|
|
44
|
+
config['default.layout'] = "surveyor_default"
|
|
45
|
+
config['default.finish'] = "/surveys"
|
|
46
|
+
config['use_restful_authentication'] = false
|
|
47
|
+
config['extend_controller'] = false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
You can update surveyor's at any time. Use the block style (above), or the individual style:
|
|
51
|
+
|
|
52
|
+
Surveyor::Config['default.title'] = "Cheese is great!"
|
|
53
|
+
|
|
54
|
+
To look at the current surveyor configuration:
|
|
55
|
+
|
|
56
|
+
Surveyor::Config.to_hash.inspect
|
|
57
|
+
|
|
58
|
+
# Extending surveyor
|
|
59
|
+
|
|
60
|
+
Surveyor's models, helper, and controller can be extended from custom modules your app/models, app/helpers and app/controllers directories. To generate the sample files and sample layout, run:
|
|
61
|
+
|
|
62
|
+
script/generate extend_surveyor
|
|
63
|
+
|
|
64
|
+
Any of surveyor's models class_eval, class methods, and instance methods can be modified. Include the following in config/initializers/surveyor.rb:
|
|
65
|
+
|
|
66
|
+
require 'models/survey_extensions' # Extended the survey model
|
|
67
|
+
|
|
68
|
+
SurveyorHelper class_eval and instance methods can be modified. Include the following in config/initializers/surveyor.rb:
|
|
69
|
+
|
|
70
|
+
require 'helpers/surveyor_helper_extensions' # Extend the surveyor helper
|
|
71
|
+
|
|
72
|
+
SurveyorController class_eval, class methods, instance methods, and actions can be modified. Action methods should be specified separately in the Actions submodule. Set the following option in config/initializers/surveyor.rb Surveyor::Config block:
|
|
73
|
+
|
|
74
|
+
config['extend_controller'] = true
|
|
75
|
+
|
|
76
|
+
# Sample layout
|
|
77
|
+
|
|
78
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
79
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
80
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
81
|
+
<head>
|
|
82
|
+
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
|
83
|
+
<title>Survey: <%= controller.action_name %></title>
|
|
84
|
+
<%= surveyor_includes # calls surveyor_javascripts + surveyor_stylesheets %>
|
|
85
|
+
</head>
|
|
86
|
+
<body>
|
|
87
|
+
<div id="flash"><%= flash[:notice] %></div>
|
|
88
|
+
<div id="survey_with_menu">
|
|
89
|
+
<%= yield %>
|
|
90
|
+
</div>
|
|
91
|
+
</body>
|
|
92
|
+
</html>
|
|
93
|
+
|
|
94
|
+
The <code>surveyor\_includes</code> helper just calls <code>surveyor\_stylsheets + surveyor\_javascripts</code> which in turn call:
|
|
95
|
+
|
|
96
|
+
stylesheet_link_tag 'surveyor/reset', 'surveyor/surveyor', 'surveyor/ui.theme.css','surveyor/jquery-ui-slider-additions'
|
|
97
|
+
|
|
98
|
+
javascript_include_tag 'surveyor/jquery-1.2.6.js', 'surveyor/jquery-ui-personalized-1.5.3.js', 'surveyor/accessibleUISlider.jQuery.js','surveyor/jquery.form.js', 'surveyor/surveyor.js'
|
|
99
|
+
|
|
100
|
+
# Dependencices
|
|
101
|
+
|
|
102
|
+
Surveyor depends on Rails 2.3 and the SASS style sheet language, part of HAML (http://haml.hamptoncatlin.com/download)
|
|
103
|
+
|
|
104
|
+
Copyright (c) 2008-2009 Brian Chamberlain and Mark Yoon, released under the MIT license
|
data/Rakefile
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'jeweler'
|
|
6
|
+
Jeweler::Tasks.new do |gem|
|
|
7
|
+
gem.name = "surveyor"
|
|
8
|
+
gem.summary = %Q{A rails (gem) plugin to enable surveys in your application}
|
|
9
|
+
gem.email = "yoon@northwestern.edu"
|
|
10
|
+
gem.homepage = "http://github.com/breakpointer/surveyor"
|
|
11
|
+
gem.authors = ["Brian Chamberlain", "Mark Yoon"]
|
|
12
|
+
gem.add_dependency 'haml'
|
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
14
|
+
end
|
|
15
|
+
Jeweler::GemcutterTasks.new
|
|
16
|
+
|
|
17
|
+
rescue LoadError
|
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
require 'spec/rake/spectask'
|
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
|
30
|
+
spec.rcov = true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
task :default => :spec
|
|
35
|
+
|
|
36
|
+
require 'rake/rdoctask'
|
|
37
|
+
Rake::RDocTask.new do |rdoc|
|
|
38
|
+
if File.exist?('VERSION.yml')
|
|
39
|
+
config = YAML.load(File.read('VERSION.yml'))
|
|
40
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
|
41
|
+
else
|
|
42
|
+
version = ""
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
46
|
+
rdoc.title = "surveyor #{version}"
|
|
47
|
+
rdoc.rdoc_files.include('README*')
|
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
49
|
+
end
|
|
50
|
+
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.6.1
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# The Surveyor controller a user taking a survey. It is semi-RESTful since it does not have a concrete representation model.
|
|
2
|
+
# The "resource" is a survey attempt/session populating a response set.
|
|
3
|
+
|
|
4
|
+
class SurveyorController < ApplicationController
|
|
5
|
+
|
|
6
|
+
# Layout
|
|
7
|
+
layout Surveyor::Config['default.layout'] || 'surveyor_default'
|
|
8
|
+
|
|
9
|
+
# Extending surveyor
|
|
10
|
+
include SurveyorControllerExtensions if Surveyor::Config['extend_controller'] && defined? SurveyorControllerExtensions
|
|
11
|
+
before_filter :extend_actions
|
|
12
|
+
|
|
13
|
+
# RESTful authentication
|
|
14
|
+
if Surveyor::Config['use_restful_authentication']
|
|
15
|
+
include AuthenticatedSystem
|
|
16
|
+
before_filter :login_required
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Get the response set or current_user
|
|
20
|
+
# before_filter :get_response_set, :except => [:new, :create]
|
|
21
|
+
before_filter :get_current_user, :only => [:new, :create]
|
|
22
|
+
|
|
23
|
+
# Actions
|
|
24
|
+
def new
|
|
25
|
+
@surveys = Survey.find(:all)
|
|
26
|
+
end
|
|
27
|
+
def create
|
|
28
|
+
if (@survey = Survey.find_by_access_code(params[:survey_code])) && (@response_set = ResponseSet.create(:survey => @survey, :user_id => @current_user))
|
|
29
|
+
flash[:notice] = "Survey was successfully started."
|
|
30
|
+
redirect_to(edit_my_survey_path(:survey_code => @survey.access_code, :response_set_code => @response_set.access_code))
|
|
31
|
+
else
|
|
32
|
+
flash[:notice] = "Unable to find that survey"
|
|
33
|
+
redirect_to(available_surveys_path)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
def show
|
|
37
|
+
end
|
|
38
|
+
def edit
|
|
39
|
+
if @response_set = ResponseSet.find_by_access_code(params[:response_set_code], :include => {:responses => [:question, :answer]})
|
|
40
|
+
@survey = Survey.with_sections.find_by_id(@response_set.survey_id)
|
|
41
|
+
@sections = @survey.sections
|
|
42
|
+
@section = params[:section] ? @sections.with_includes.find(section_id_from(params[:section])) || @sections.with_includes.first : @sections.with_includes.first
|
|
43
|
+
else
|
|
44
|
+
flash[:notice] = "Unable to find your responses to the survey"
|
|
45
|
+
redirect_to(available_surveys_path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@dependents = (@response_set.unanswered_dependencies - @section.questions) || []
|
|
49
|
+
end
|
|
50
|
+
def update
|
|
51
|
+
if @response_set = ResponseSet.find_by_access_code(params[:response_set_code], :include => {:responses => :answer})
|
|
52
|
+
@response_set.current_section_id = params[:current_section_id]
|
|
53
|
+
else
|
|
54
|
+
flash[:notice] = "Unable to find your responses to the survey"
|
|
55
|
+
redirect_to(available_surveys_path)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if params[:responses] or params[:response_groups]
|
|
59
|
+
@response_set.clear_responses
|
|
60
|
+
saved = @response_set.update_attributes(:response_attributes => (params[:responses] || {}).dup , :response_group_attributes => (params[:response_groups] || {}).dup) #copy (dup) to preserve params because we manipulate params in the response_set methods
|
|
61
|
+
if (saved && params[:finish])
|
|
62
|
+
@response_set.complete!
|
|
63
|
+
saved = @response_set.save!
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
respond_to do |format|
|
|
67
|
+
format.html do
|
|
68
|
+
if saved && params[:finish]
|
|
69
|
+
flash[:notice] = "Completed survey"
|
|
70
|
+
redirect_to surveyor_default_finish
|
|
71
|
+
else
|
|
72
|
+
flash[:notice] = "Unable to update survey" if !saved and !saved.nil? # saved.nil? is true if there are no questions on the page (i.e. if it only contains a label)
|
|
73
|
+
redirect_to :action => "edit", :anchor => anchor_from(params[:section]), :params => {:section => section_id_from(params[:section])}
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
# No redirect needed if we're talking to the page via json
|
|
77
|
+
format.js do
|
|
78
|
+
render :json => @response_set.all_dependencies.to_json
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# Filters
|
|
86
|
+
def get_current_user
|
|
87
|
+
@current_user = self.respond_to?(:current_user) ? self.current_user : nil
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Params: the name of some submit buttons store the section we'd like to go to. for repeater questions, an anchor to the repeater group is also stored
|
|
91
|
+
# e.g. params[:section] = {"1"=>{"question_group_1"=>"<= add row"}}
|
|
92
|
+
def section_id_from(p)
|
|
93
|
+
p.respond_to?(:keys) ? p.keys.first : p
|
|
94
|
+
end
|
|
95
|
+
def anchor_from(p)
|
|
96
|
+
p.respond_to?(:keys) && p[p.keys.first].respond_to?(:keys) ? p[p.keys.first].keys.first : nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Extending surveyor
|
|
100
|
+
def surveyor_default_finish
|
|
101
|
+
# http://www.postal-code.com/mrhappy/blog/2007/02/01/ruby-comparing-an-objects-class-in-a-case-statement/
|
|
102
|
+
# http://www.skorks.com/2009/08/how-a-ruby-case-statement-works-and-what-you-can-do-with-it/
|
|
103
|
+
case finish = Surveyor::Config['default.finish']
|
|
104
|
+
when String
|
|
105
|
+
return finish
|
|
106
|
+
when Symbol
|
|
107
|
+
return self.send(finish)
|
|
108
|
+
else
|
|
109
|
+
return '/surveys'
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
def extend_actions
|
|
113
|
+
# http://blog.mattwynne.net/2009/07/11/rails-tip-use-polymorphism-to-extend-your-controllers-at-runtime/
|
|
114
|
+
self.extend SurveyorControllerExtensions::Actions if Surveyor::Config['extend_controller'] && defined? SurveyorControllerExtensions::Actions
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class SurveyFormBuilder < ActionView::Helpers::FormBuilder
|
|
2
|
+
def survey_check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
|
3
|
+
fields = @template.survey_check_box(@object_name, method, options.merge(:object => @object), checked_value, unchecked_value)
|
|
4
|
+
fields[1]
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ActionView
|
|
9
|
+
module Helpers
|
|
10
|
+
module FormHelper
|
|
11
|
+
def survey_check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
|
|
12
|
+
if (Rails::VERSION::STRING.to_f > 2.1)
|
|
13
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_survey_check_box_tag(options, checked_value, unchecked_value)
|
|
14
|
+
else
|
|
15
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_survey_check_box_tag(options, checked_value, unchecked_value)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class InstanceTag
|
|
21
|
+
def to_survey_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
|
|
22
|
+
options = options.stringify_keys
|
|
23
|
+
options["type"] = "checkbox"
|
|
24
|
+
options["value"] = checked_value
|
|
25
|
+
if options.has_key?("checked")
|
|
26
|
+
cv = options.delete "checked"
|
|
27
|
+
checked = cv == true || cv == "checked"
|
|
28
|
+
else
|
|
29
|
+
checked = self.class.check_box_checked?(value(object), checked_value)
|
|
30
|
+
end
|
|
31
|
+
options["checked"] = "checked" if checked
|
|
32
|
+
add_default_name_and_id(options)
|
|
33
|
+
[tag("input", "name" => options["name"], "type" => "hidden", "value" => unchecked_value), tag("input", options)]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module SurveyorHelper
|
|
2
|
+
|
|
3
|
+
# Configuration
|
|
4
|
+
def surveyor_config
|
|
5
|
+
Surveyor::Config
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Layout: stylsheets and javascripts
|
|
9
|
+
def surveyor_includes
|
|
10
|
+
surveyor_stylsheets + surveyor_javascripts
|
|
11
|
+
end
|
|
12
|
+
def surveyor_stylsheets
|
|
13
|
+
stylesheet_link_tag 'surveyor/reset', 'surveyor/surveyor', 'surveyor/ui.theme.css','surveyor/jquery-ui-slider-additions'
|
|
14
|
+
end
|
|
15
|
+
def surveyor_javascripts
|
|
16
|
+
javascript_include_tag 'surveyor/jquery-1.2.6.js', 'surveyor/jquery-ui-personalized-1.5.3.js', 'surveyor/accessibleUISlider.jQuery.js','surveyor/jquery.form.js', 'surveyor/surveyor.js'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Section: dependencies, menu, previous and next
|
|
20
|
+
def dependency_explanation_helper(question,response_set)
|
|
21
|
+
# Attempts to explain why this dependent question needs to be answered by referenced the dependent question and users response
|
|
22
|
+
trigger_responses = []
|
|
23
|
+
dependent_questions = Question.find_all_by_id(question.dependency.dependency_conditions.map(&:question_id)).uniq
|
|
24
|
+
response_set.responses.find_all_by_question_id(dependent_questions.map(&:id)).uniq.each do |resp|
|
|
25
|
+
trigger_responses << resp.to_s
|
|
26
|
+
end
|
|
27
|
+
" You answered "#{trigger_responses.join("" and "")}" to the question "#{dependent_questions.map(&:text).join("","")}""
|
|
28
|
+
end
|
|
29
|
+
def menu_button_for(section)
|
|
30
|
+
submit_tag(section.title, :name => "section[#{section.id}]")
|
|
31
|
+
end
|
|
32
|
+
def previous_section
|
|
33
|
+
# submit_tag("« Previous section", :name => "section[#{@section.previous.id}]") unless @section.previous.nil?
|
|
34
|
+
# refactored to use copy in memory instead of making extra db calls
|
|
35
|
+
submit_tag("« Previous section", :name => "section[#{@sections[@sections.index(@section)-1].id}]") unless @sections.first == @section
|
|
36
|
+
end
|
|
37
|
+
def next_section
|
|
38
|
+
# @section.next.nil? ? submit_tag("Click here to finish", :name => "finish") : submit_tag("Next section »", :name => "section[#{@section.next.id}]")
|
|
39
|
+
# refactored to use copy in memory instead of making extra db calls
|
|
40
|
+
@sections.last == @section ? submit_tag("Click here to finish", :name => "finish") : submit_tag("Next section »", :name => "section[#{@sections[@sections.index(@section)+1].id}]")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Questions
|
|
44
|
+
def next_number
|
|
45
|
+
@n ||= 0
|
|
46
|
+
"#{@n += 1}<span style='padding-left:0.1em;'>)</span>"
|
|
47
|
+
end
|
|
48
|
+
def split_text(text = "") # Split text into with "|" delimiter - parts to go before/after input element
|
|
49
|
+
{:prefix => text.split("|")[0].blank? ? " " : text.split("|")[0], :postfix => text.split("|")[1] || " "}
|
|
50
|
+
end
|
|
51
|
+
def question_help_helper(question)
|
|
52
|
+
question.help_text.blank? ? "" : %Q(<span class="question-help">#{question.help_text}</span>)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Answers
|
|
56
|
+
def fields_for_response(response, &block)
|
|
57
|
+
fields_for("responses[#{response.question_id}][#{response.answer_id}]", response, :builder => SurveyFormBuilder, &block)
|
|
58
|
+
end
|
|
59
|
+
def fields_for_repeater_response(response, response_group, &block) # Changes the response hash to accept response groups for repeater elements
|
|
60
|
+
fields_for("response_groups[#{response.question_id}][#{response_group}][#{response.answer_id}]", response, :builder => SurveyFormBuilder, &block)
|
|
61
|
+
end
|
|
62
|
+
def fields_for_radio(response, &block)
|
|
63
|
+
fields_for("responses[#{response.question_id}]", response, :builder => SurveyFormBuilder, &block)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class Answer < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
# Associations
|
|
4
|
+
belongs_to :question
|
|
5
|
+
has_many :responses
|
|
6
|
+
|
|
7
|
+
# Scopes
|
|
8
|
+
default_scope :order => "display_order ASC"
|
|
9
|
+
|
|
10
|
+
# Validations
|
|
11
|
+
validates_presence_of :text
|
|
12
|
+
validates_numericality_of :question_id, :allow_nil => false, :only_integer => true
|
|
13
|
+
#validates_uniqueness_of :reference_identifier
|
|
14
|
+
|
|
15
|
+
# Methods
|
|
16
|
+
def renderer(q = question)
|
|
17
|
+
r = [q.pick.to_s, self.response_class].compact.join("_")
|
|
18
|
+
r.blank? ? :default : r.to_sym
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class Dependency < ActiveRecord::Base
|
|
2
|
+
# Associations
|
|
3
|
+
belongs_to :question
|
|
4
|
+
has_many :dependency_conditions
|
|
5
|
+
|
|
6
|
+
# Scopes
|
|
7
|
+
named_scope :depending_on_questions, lambda {|question_ids| {:include => :dependency_conditions, :conditions => {:dependency_conditions => {:question_id => question_ids}} }}
|
|
8
|
+
|
|
9
|
+
# Validations
|
|
10
|
+
validates_presence_of :rule
|
|
11
|
+
validates_format_of :rule, :with => /^(?:and|or|\)|\(|\d|\s)+$/ #TODO properly formed parenthesis etc.
|
|
12
|
+
validates_numericality_of :question_id
|
|
13
|
+
|
|
14
|
+
# Attribute aliases
|
|
15
|
+
alias_attribute :dependent_question_id, :question_id
|
|
16
|
+
|
|
17
|
+
# Is the method that determines if this dependency has been met within
|
|
18
|
+
# the provided response set
|
|
19
|
+
def met?(response_set)
|
|
20
|
+
if keyed_pairs = keyed_conditions(response_set)
|
|
21
|
+
return(rule_evaluation(keyed_pairs))
|
|
22
|
+
else
|
|
23
|
+
return(false)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Pairs up the substitution key with the evaluated condition result for substitution into the rule
|
|
28
|
+
# Example: If you have two dependency conditions with rule keys "A" and "B" in the rule "A or B"
|
|
29
|
+
# calling keyed_condition_pairs will return {:A => true, :B => false}
|
|
30
|
+
def keyed_conditions(response_set)
|
|
31
|
+
keyed_pairs = {}
|
|
32
|
+
self.dependency_conditions.each do |dc|
|
|
33
|
+
keyed_pairs.merge!(dc.to_evaluation_hash(response_set))
|
|
34
|
+
end
|
|
35
|
+
return(keyed_pairs)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Does the substiution and evaluation of the dependency rule with the keyed pairs
|
|
39
|
+
def rule_evaluation(keyed_pairs)
|
|
40
|
+
# subtitute into rule for evaluation
|
|
41
|
+
rgx = Regexp.new(self.dependency_conditions.map{|dc| dc.rule_key}.join("|")) # Making a regexp to only look for the keys used in the child conditions
|
|
42
|
+
#logger.debug("rexp: #{rgx.inspect} FOO: #{keyed_pairs.inspect} --- subbed rules: #{rule.gsub(rgx){|m| keyed_pairs[m.to_sym]}} --> #{eval(self.rule.gsub(rgx){|m| keyed_pairs[m.to_sym]})}")
|
|
43
|
+
eval(self.rule.gsub(rgx){|m| keyed_pairs[m.to_sym]}) # returns the evaluation of the rule and the conditions
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|