surveyor 0.10.0 → 0.11.0

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/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