surveyor 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -106,15 +106,16 @@ The surveyor generator creates config/initializers/surveyor.rb. There, you can s
106
106
  The initializer runs once, when the app starts. The block style is used to keep multiple options DRY (defaults below):
107
107
 
108
108
  Surveyor::Config.run do |config|
109
- config['default.relative_url_root'] = "surveys/" # should end with '/'
110
- config['default.title'] = "You can take these surveys:"
111
- config['default.layout'] = "surveyor_default"
112
- config['default.finish'] = "/surveys"
113
- config['use_restful_authentication'] = false
114
- config['extend_controller'] = false
109
+ config['default.relative_url_root'] = nil # "surveys"
110
+ config['default.title'] = nil # "You can take these surveys:"
111
+ config['default.layout'] = nil # "surveyor_default"
112
+ config['default.index'] = nil # "/surveys" # or :index_path_method
113
+ config['default.finish'] = nil # "/surveys" # or :finish_path_method
114
+ config['use_restful_authentication'] = false # set to true to use restful authentication
115
+ config['extend'] = %w() # %w(survey surveyor_helper surveyor_controller)
115
116
  end
116
-
117
- You can update surveyor's at any time. Use the block style (above), or the individual style:
117
+
118
+ You can update surveyor's configuration at any time. Use the block style (above), or the individual style:
118
119
 
119
120
  Surveyor::Config['default.title'] = "Cheese is great!"
120
121
 
@@ -152,9 +153,7 @@ SurveyorController class_eval, class methods, instance methods, and actions can
152
153
  </head>
153
154
  <body>
154
155
  <div id="flash"><%= flash[:notice] %></div>
155
- <div id="survey_with_menu">
156
- <%= yield %>
157
- </div>
156
+ <%= yield %>
158
157
  </body>
159
158
  </html>
160
159
 
@@ -175,6 +174,26 @@ To work on the plugin code (for enhancements, and bug fixes, etc...) fork this g
175
174
 
176
175
  # Changes
177
176
 
177
+ 0.11.0
178
+
179
+ * basic csv export. closes #21
180
+ * add unique indicies. closes #45
181
+ * add one_integer renderer. closes #51
182
+ * constrain surveys to have unique access_codes. closes #45. closes #42
183
+ * covering the extremely unlikely case that response_sets may have a non-unique access_code. closes #46. thanks jakewendt.
184
+ * current user id not needed in the view, set in SurveyorController. closes #48. thanks jakewendt
185
+
186
+ 0.10.0
187
+
188
+ * surveyor config['extend'] is now an array. custom modules (e.g. SurveyExtensions are now included from within surveyor models, allowing
189
+ the customizations to work on every request in development. closes #39. thanks to mgurley and jakewendt for the suggestions.
190
+ * remove comment from surveyor_includes
191
+ * css tweak
192
+ * automatically add backslashes and eliminate multiple backslashes in relative root for routes
193
+ * readme spelling and line breaks
194
+ * fixing a failing spec with factory instead of mock parent model
195
+ * upgrading cucumber to 0.6
196
+
178
197
  0.9.11
179
198
 
180
199
  * adding rails init.rb to make gem loading work. thanks mike gurley. closes #52.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 0.11.0
@@ -39,6 +39,13 @@ class SurveyorController < ApplicationController
39
39
  end
40
40
 
41
41
  def show
42
+ @response_set = ResponseSet.find_by_access_code(params[:response_set_code], :include => {:responses => [:question, :answer]})
43
+ respond_to do |format|
44
+ format.html #{render :action => :show}
45
+ format.csv {
46
+ send_data(@response_set.to_csv, :type => 'text/csv; charset=utf-8; header=present',:filename => "#{@response_set.updated_at.strftime('%Y-%m-%d')}_#{@response_set.access_code}.csv")
47
+ }
48
+ end
42
49
  end
43
50
 
44
51
  def edit
@@ -11,6 +11,7 @@ class ResponseSet < ActiveRecord::Base
11
11
  # Validations
12
12
  validates_presence_of :survey_id
13
13
  validates_associated :responses
14
+ validates_uniqueness_of :access_code
14
15
 
15
16
  # Attributes
16
17
  attr_protected :completed_at
@@ -30,6 +31,27 @@ class ResponseSet < ActiveRecord::Base
30
31
  self.access_code = Surveyor.make_tiny_code
31
32
  end
32
33
 
34
+ def access_code=(val)
35
+ while ResponseSet.find_by_access_code(val)
36
+ val = Surveyor.make_tiny_code
37
+ end
38
+ super
39
+ end
40
+
41
+ def to_csv
42
+ qcols = Question.content_columns.map(&:name) - %w(created_at updated_at)
43
+ acols = Answer.content_columns.map(&:name) - %w(created_at updated_at)
44
+ rcols = Response.content_columns.map(&:name)
45
+ require 'fastercsv'
46
+ FCSV(result = "") do |csv|
47
+ csv << qcols.map{|qcol| "question.#{qcol}"} + acols.map{|acol| "answer.#{acol}"} + rcols.map{|rcol| "response.#{rcol}"}
48
+ responses.each do |response|
49
+ csv << qcols.map{|qcol| response.question.send(qcol)} + acols.map{|acol| response.answer.send(acol)} + rcols.map{|rcol| response.send(rcol)}
50
+ end
51
+ end
52
+ result
53
+ end
54
+
33
55
  def response_for(question_id, answer_id, group = nil)
34
56
  found = responses.detect{|r| r.question_id == question_id && r.answer_id == answer_id && r.response_group.to_s == group.to_s}
35
57
  found.blank? ? responses.new(:question_id => question_id, :answer_id => answer_id, :response_group => group) : found
data/app/models/survey.rb CHANGED
@@ -13,6 +13,7 @@ class Survey < ActiveRecord::Base
13
13
 
14
14
  # Validations
15
15
  validates_presence_of :title
16
+ validates_uniqueness_of :access_code
16
17
 
17
18
  # Class methods
18
19
  def self.to_normalized_string(value)
@@ -16,20 +16,23 @@
16
16
  = response_form.survey_check_box(:selected, :class => (answer.is_exclusive? ? "exclusive" : ""))
17
17
  = response_form.label(:answer_id, answer.text)
18
18
  = response_form.text_field(:string_value, :size => 25, :maxlength => 250)
19
- - when :one_answer, :one_string
19
+ - when :one_answer, :one_string, :one_integer
20
20
  - fields_for_radio(response_obj) do |radio_form|
21
21
  = radio_form.radio_button(:answer_id, answer.id, :checked => response_obj.selected?, :title => answer.text)
22
- = radio_form.label("answer_id_#{answer.id}", answer.text, :class => (hide_label ? "hidden" : ""))
23
- - if renderer == :one_string
24
- = response_form.text_field(:string_value, :size => 25, :maxlength => 250, :autocomplete => "off")
22
+ = radio_form.label("answer_id_#{answer.id}", split_text(answer.text)[:prefix]) unless hide_label
23
+ - if renderer == :one_string
24
+ = response_form.text_field(:string_value, :size => 25, :maxlength => 250, :autocomplete => "off")
25
+ - if renderer == :one_integer
26
+ = response_form.text_field(:integer_value, :size => 5, :maxlength => 10, :autocomplete => "off")
27
+ = radio_form.label("answer_id_#{answer.id}", split_text(answer.text)[:postfix]) unless hide_label
25
28
  - when :none_date
26
- = response_form.label(:string_value, split_text(answer.text)[:prefix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
29
+ = response_form.label(:datetime_value, split_text(answer.text)[:prefix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
27
30
  = response_form.text_field(:datetime_value)
28
- = response_form.label(:string_value, split_text(answer.text)[:postfix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
31
+ = response_form.label(:datetime_value, split_text(answer.text)[:postfix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
29
32
  - when :none_datetime
30
- = response_form.label(:string_value, split_text(answer.text)[:prefix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
33
+ = response_form.label(:datetime_value, split_text(answer.text)[:prefix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
31
34
  = response_form.datetime_select(:datetime_value, {:include_blank => true})
32
- = response_form.label(:string_value, split_text(answer.text)[:postfix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
35
+ = response_form.label(:datetime_value, split_text(answer.text)[:postfix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
33
36
  - when :none_float
34
37
  = response_form.label(:float_value, split_text(answer.text)[:prefix]) unless hide_label
35
38
  = response_form.text_field(:float_value, :size => 5, :maxlength => 10, :autocomplete => "off")
@@ -47,9 +50,9 @@
47
50
  = response_form.text_area(:text_value, :cols => 80, :rows => 10)
48
51
  = response_form.label(:text_value, split_text(answer.text)[:postfix]) unless hide_label
49
52
  - when :none_time
50
- = response_form.label(:string_value, split_text(answer.text)[:prefix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
53
+ = response_form.label(:datetime_value, split_text(answer.text)[:prefix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
51
54
  = response_form.time_select(:datetime_value,{ :include_blank => true })
52
- = response_form.label(:string_value, split_text(answer.text)[:postfix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
55
+ = response_form.label(:datetime_value, split_text(answer.text)[:postfix], :class => "#{(disabled)? 'disabled' : 'enabled'}") unless hide_label
53
56
  - else
54
57
  = answer.text
55
58
 
@@ -8,7 +8,6 @@
8
8
  - @surveys.each do |survey|
9
9
  %li
10
10
  - form_tag(take_survey_path(:survey_code => survey.access_code)) do
11
- = hidden_field_tag("current_user_id", @current_user.nil? ? nil : @current_user.id)
12
11
  = survey.title
13
12
  &nbsp;
14
13
  = submit_tag("Take it" )
data/config/routes.rb CHANGED
@@ -2,10 +2,10 @@ ActionController::Routing::Routes.draw do |map|
2
2
  root = Surveyor::Config['default.relative_url_root'] || "surveys"
3
3
  root = (root << "/").gsub(/\/+/, "/")
4
4
  map.with_options :controller => 'surveyor' do |s|
5
- s.available_surveys "#{root}", :conditions => {:method => :get}, :action => "new" # GET survey list
6
- s.take_survey "#{root}:survey_code", :conditions => {:method => :post}, :action => "create" # Only POST of survey to create
7
- s.view_my_survey "#{root}:survey_code/:response_set_code", :conditions => {:method => :get}, :action => "show" # GET viewable/printable? survey
8
- s.edit_my_survey "#{root}:survey_code/:response_set_code/take", :conditions => {:method => :get}, :action => "edit" # GET editable survey
9
- s.update_my_survey "#{root}:survey_code/:response_set_code", :conditions => {:method => :put}, :action => "update" # PUT edited survey
5
+ s.available_surveys "#{root}", :conditions => {:method => :get}, :action => "new" # GET survey list
6
+ s.take_survey "#{root}:survey_code", :conditions => {:method => :post}, :action => "create" # Only POST of survey to create
7
+ s.view_my_survey "#{root}:survey_code/:response_set_code.:format", :conditions => {:method => :get}, :action => "show", :format => "html" # GET viewable/printable? survey
8
+ s.edit_my_survey "#{root}:survey_code/:response_set_code/take", :conditions => {:method => :get}, :action => "edit" # GET editable survey
9
+ s.update_my_survey "#{root}:survey_code/:response_set_code", :conditions => {:method => :put}, :action => "update" # PUT edited survey
10
10
  end
11
11
  end
@@ -29,7 +29,8 @@ class SurveyorGenerator < Rails::Generator::Base
29
29
  "create_response_sets", "create_responses",
30
30
  "create_dependencies", "create_dependency_conditions",
31
31
  "create_validations", "create_validation_conditions",
32
- "add_display_order_to_surveys", "add_correct_answer_id_to_questions"].each_with_index do |model, i|
32
+ "add_display_order_to_surveys", "add_correct_answer_id_to_questions",
33
+ "add_index_to_response_sets", "add_index_to_surveys", "add_unique_indicies"].each_with_index do |model, i|
33
34
  unless (prev_migrations = Dir.glob("db/migrate/[0-9]*_*.rb").grep(/[0-9]+_#{model}.rb$/)).empty?
34
35
  prev_migration_timestamp = prev_migrations[0].match(/([0-9]+)_#{model}.rb$/)[1]
35
36
  end
@@ -0,0 +1,9 @@
1
+ class AddIndexToResponseSets < ActiveRecord::Migration
2
+ def self.up
3
+ add_index(:response_sets, :access_code, :name => 'response_sets_ac_idx')
4
+ end
5
+
6
+ def self.down
7
+ remove_index(:response_sets, :name => 'response_sets_ac_idx')
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class AddIndexToSurveys < ActiveRecord::Migration
2
+ def self.up
3
+ add_index(:surveys, :access_code, :name => 'surveys_ac_idx')
4
+ end
5
+
6
+ def self.down
7
+ remove_index(:surveys, :name => 'surveys_ac_idx')
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ class AddUniqueIndicies < ActiveRecord::Migration
2
+ def self.up
3
+ remove_index(:response_sets, :name => 'response_sets_ac_idx')
4
+ add_index(:response_sets, :access_code, :name => 'response_sets_ac_idx', :unique => true)
5
+
6
+ remove_index(:surveys, :name => 'surveys_ac_idx')
7
+ add_index(:surveys, :access_code, :name => 'surveys_ac_idx', :unique => true)
8
+ end
9
+
10
+ def self.down
11
+ remove_index(:response_sets, :name => 'response_sets_ac_idx')
12
+ add_index(:response_sets, :access_code, :name => 'response_sets_ac_idx')
13
+
14
+ remove_index(:surveys, :name => 'surveys_ac_idx')
15
+ add_index(:surveys, :access_code, :name => 'surveys_ac_idx')
16
+ end
17
+ end
data/spec/factories.rb CHANGED
@@ -2,10 +2,12 @@
2
2
  require 'rubygems'
3
3
  require 'factory_girl'
4
4
 
5
+ Factory.sequence(:unique_survey_access_code){|n| "simple_survey" << n.to_s }
6
+
5
7
  Factory.define :survey do |s|
6
8
  s.title {"Simple survey"}
7
9
  s.description {"A simple survey for testing"}
8
- s.access_code {"simple_survey"}
10
+ s.access_code {Factory.next :unique_survey_access_code}
9
11
  s.active_at {Time.now}
10
12
  s.inactive_at {}
11
13
  s.css_url {}
@@ -215,4 +215,31 @@ describe ResponseSet, "with mandatory, dependent questions" do
215
215
  @response_set.mandatory_questions_complete?.should be_true
216
216
  @response_set.progress_hash.should == {:questions => 4, :triggered => 4, :triggered_mandatory => 4, :triggered_mandatory_completed => 4}
217
217
  end
218
+ end
219
+ describe ResponseSet, "exporting csv" do
220
+ before(:each) do
221
+ @section = Factory(:survey_section)
222
+ # Questions
223
+ @do_you_like_pie = Factory(:question, :text => "Do you like pie?", :survey_section => @section)
224
+ @what_flavor = Factory(:question, :text => "What flavor?", :survey_section => @section)
225
+ @what_bakery = Factory(:question, :text => "What bakery?", :survey_section => @section)
226
+ # Answers
227
+ @do_you_like_pie.answers << Factory(:answer, :text => "yes", :question_id => @do_you_like_pie.id)
228
+ @do_you_like_pie.answers << Factory(:answer, :text => "no", :question_id => @do_you_like_pie.id)
229
+ @what_flavor.answers << Factory(:answer, :response_class => :string, :question_id => @what_flavor.id)
230
+ @what_bakery.answers << Factory(:answer, :response_class => :string, :question_id => @what_bakery.id)
231
+ # Responses
232
+ @response_set = Factory(:response_set)
233
+ @response_set.current_section_id = @section.id
234
+ @response_set.responses << Factory(:response, :question_id => @do_you_like_pie.id, :answer_id => @do_you_like_pie.answers.first.id, :response_set_id => @response_set.id)
235
+ @response_set.responses << Factory(:response, :string_value => "pecan pie", :question_id => @what_flavor.id, :answer_id => @what_flavor.answers.first.id, :response_set_id => @response_set.id)
236
+ end
237
+ it "should export a string with responses" do
238
+ @response_set.responses.size.should == 2
239
+ csv = @response_set.to_csv
240
+ csv.is_a?(String).should be_true
241
+ csv.should match "question.short_text"
242
+ csv.should match "What flavor?"
243
+ csv.should match /pecan pie/
244
+ end
218
245
  end
data/surveyor.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{surveyor}
8
- s.version = "0.10.0"
8
+ s.version = "0.11.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brian Chamberlain", "Mark Yoon"]
12
- s.date = %q{2010-04-05}
12
+ s.date = %q{2010-04-06}
13
13
  s.email = %q{yoon@northwestern.edu}
14
14
  s.extra_rdoc_files = [
15
15
  "README.md"
@@ -111,6 +111,9 @@ Gem::Specification.new do |s|
111
111
  "generators/surveyor/templates/initializers/surveyor.rb",
112
112
  "generators/surveyor/templates/migrate/add_correct_answer_id_to_questions.rb",
113
113
  "generators/surveyor/templates/migrate/add_display_order_to_surveys.rb",
114
+ "generators/surveyor/templates/migrate/add_index_to_response_sets.rb",
115
+ "generators/surveyor/templates/migrate/add_index_to_surveys.rb",
116
+ "generators/surveyor/templates/migrate/add_unique_indicies.rb",
114
117
  "generators/surveyor/templates/migrate/create_answers.rb",
115
118
  "generators/surveyor/templates/migrate/create_dependencies.rb",
116
119
  "generators/surveyor/templates/migrate/create_dependency_conditions.rb",
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 10
7
+ - 11
8
8
  - 0
9
- version: 0.10.0
9
+ version: 0.11.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Chamberlain
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-04-05 00:00:00 -05:00
18
+ date: 2010-04-06 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -135,6 +135,9 @@ files:
135
135
  - generators/surveyor/templates/initializers/surveyor.rb
136
136
  - generators/surveyor/templates/migrate/add_correct_answer_id_to_questions.rb
137
137
  - generators/surveyor/templates/migrate/add_display_order_to_surveys.rb
138
+ - generators/surveyor/templates/migrate/add_index_to_response_sets.rb
139
+ - generators/surveyor/templates/migrate/add_index_to_surveys.rb
140
+ - generators/surveyor/templates/migrate/add_unique_indicies.rb
138
141
  - generators/surveyor/templates/migrate/create_answers.rb
139
142
  - generators/surveyor/templates/migrate/create_dependencies.rb
140
143
  - generators/surveyor/templates/migrate/create_dependency_conditions.rb