census 0.1.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/LICENSE +20 -0
- data/README.rdoc +5 -0
- data/Rakefile +70 -0
- data/VERSION +1 -0
- data/app/controllers/census/data_groups_controller.rb +44 -0
- data/app/helpers/census_helper.rb +15 -0
- data/app/models/answer.rb +43 -0
- data/app/models/choice.rb +9 -0
- data/app/models/data_group.rb +10 -0
- data/app/models/question.rb +54 -0
- data/app/views/census/_question_fields.html.erb +40 -0
- data/app/views/census/_user_answers.html.erb +10 -0
- data/app/views/census/_user_questions.html.erb +10 -0
- data/app/views/census/data_groups/_choice_fields.html.erb +4 -0
- data/app/views/census/data_groups/_form.html.erb +11 -0
- data/app/views/census/data_groups/_question_fields.html.erb +22 -0
- data/app/views/census/data_groups/edit.html.erb +7 -0
- data/app/views/census/data_groups/index.html.erb +10 -0
- data/app/views/census/data_groups/new.html.erb +7 -0
- data/config/routes.rb +8 -0
- data/generators/census/USAGE +1 -0
- data/generators/census/census_generator.rb +39 -0
- data/generators/census/lib/insert_commands.rb +33 -0
- data/generators/census/lib/rake_commands.rb +22 -0
- data/generators/census/templates/README +29 -0
- data/generators/census/templates/census.js +10 -0
- data/generators/census/templates/census.rb +14 -0
- data/generators/census/templates/factories.rb +24 -0
- data/generators/census/templates/migrations/with_users.rb +60 -0
- data/generators/census/templates/migrations/without_users.rb +54 -0
- data/generators/census/templates/user.rb +3 -0
- data/lib/census/data_type.rb +33 -0
- data/lib/census/user.rb +85 -0
- data/lib/census.rb +1 -0
- data/rails/init.rb +7 -0
- data/shoulda_macros/census.rb +35 -0
- data/test/controllers/data_groups_controller_test.rb +165 -0
- data/test/models/answer_test.rb +44 -0
- data/test/models/choice_test.rb +24 -0
- data/test/models/data_group_test.rb +12 -0
- data/test/models/question_test.rb +213 -0
- data/test/models/user_test.rb +9 -0
- data/test/rails_root/app/controllers/application_controller.rb +10 -0
- data/test/rails_root/app/helpers/application_helper.rb +3 -0
- data/test/rails_root/app/models/user.rb +3 -0
- data/test/rails_root/config/boot.rb +110 -0
- data/test/rails_root/config/environment.rb +8 -0
- data/test/rails_root/config/environments/development.rb +17 -0
- data/test/rails_root/config/environments/production.rb +28 -0
- data/test/rails_root/config/environments/test.rb +32 -0
- data/test/rails_root/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_root/config/initializers/census.rb +14 -0
- data/test/rails_root/config/initializers/inflections.rb +10 -0
- data/test/rails_root/config/initializers/mime_types.rb +5 -0
- data/test/rails_root/config/initializers/new_rails_defaults.rb +21 -0
- data/test/rails_root/config/initializers/session_store.rb +15 -0
- data/test/rails_root/config/routes.rb +43 -0
- data/test/rails_root/db/migrate/20100406160306_create_census_tables.rb +60 -0
- data/test/rails_root/db/schema.rb +58 -0
- data/test/rails_root/test/factories/census.rb +24 -0
- data/test/rails_root/test/performance/browsing_test.rb +9 -0
- data/test/rails_root/test/test_helper.rb +38 -0
- data/test/rails_root/vendor/gems/acts_as_list-0.1.2/lib/acts_as_list.rb +254 -0
- data/test/rails_root/vendor/gems/acts_as_list-0.1.2/test/list_test.rb +369 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/install.rb +1 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/lib/inverse_of.rb +293 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/rails/init.rb +1 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/cases/helper.rb +28 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/cases/inverse_associations_test.rb +567 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/club.rb +13 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/face.rb +7 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/interest.rb +5 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/man.rb +9 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/sponsor.rb +4 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/zine.rb +3 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/schema/schema.rb +32 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/uninstall.rb +1 -0
- data/test/test_helper.rb +19 -0
- metadata +190 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 Envy Labs LLC
|
|
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
data/Rakefile
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
require 'rake/testtask'
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'jeweler'
|
|
7
|
+
Jeweler::Tasks.new do |gem|
|
|
8
|
+
gem.name = "census"
|
|
9
|
+
gem.summary = %Q{Rails user demographics collection and searching}
|
|
10
|
+
gem.description = %Q{Census is a Rails plugin that collects searchable demographics data for each of your application's users.}
|
|
11
|
+
gem.email = "mark@envylabs.com"
|
|
12
|
+
gem.homepage = "http://github.com/envylabs/census"
|
|
13
|
+
gem.authors = ["Mark Kendall"]
|
|
14
|
+
gem.files = FileList["[A-Z]*", "{app,config,generators,lib,shoulda_macros,rails}/**/*"]
|
|
15
|
+
|
|
16
|
+
gem.add_dependency "acts_as_list", ">= 0.1.2"
|
|
17
|
+
gem.add_dependency "inverse_of", ">= 0.0.1"
|
|
18
|
+
|
|
19
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
|
20
|
+
gem.add_development_dependency "factory_girl", ">= 0"
|
|
21
|
+
end
|
|
22
|
+
Jeweler::GemcutterTasks.new
|
|
23
|
+
rescue LoadError
|
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
namespace :test do
|
|
28
|
+
Rake::TestTask.new(:basic => ["check_dependencies",
|
|
29
|
+
"generator:cleanup",
|
|
30
|
+
"generator:census"]) do |task|
|
|
31
|
+
task.libs << "lib"
|
|
32
|
+
task.libs << "test"
|
|
33
|
+
task.pattern = "test/{controllers,models}/*_test.rb"
|
|
34
|
+
task.verbose = false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
task :default => ['test:basic']
|
|
39
|
+
|
|
40
|
+
generators = %w(census)
|
|
41
|
+
|
|
42
|
+
namespace :generator do
|
|
43
|
+
desc "Cleans up the test app before running the generator"
|
|
44
|
+
task :cleanup do
|
|
45
|
+
FileList["test/rails_root/db/**/*"].each do |each|
|
|
46
|
+
FileUtils.rm_rf(each)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
FileUtils.rm_rf("test/rails_root/vendor/plugins/census")
|
|
50
|
+
FileUtils.mkdir_p("test/rails_root/vendor/plugins")
|
|
51
|
+
census_root = File.expand_path(File.dirname(__FILE__))
|
|
52
|
+
system("ln -s \"#{census_root}\" test/rails_root/vendor/plugins/census")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
desc "Run the census generator"
|
|
56
|
+
task :census do
|
|
57
|
+
system "cd test/rails_root && ./script/generate census -f && rake gems:unpack && rake db:migrate db:test:prepare"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
require 'rake/rdoctask'
|
|
63
|
+
Rake::RDocTask.new do |rdoc|
|
|
64
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
|
65
|
+
|
|
66
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
67
|
+
rdoc.title = "Census #{version}"
|
|
68
|
+
rdoc.rdoc_files.include('README*')
|
|
69
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
70
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Census::DataGroupsController < ApplicationController
|
|
2
|
+
|
|
3
|
+
def index
|
|
4
|
+
@data_groups = DataGroup.all(:order => :position)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def new
|
|
8
|
+
@data_group = DataGroup.new(params[:data_group])
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def create
|
|
12
|
+
@data_group = DataGroup.new(params[:data_group])
|
|
13
|
+
|
|
14
|
+
if @data_group.save
|
|
15
|
+
flash[:notice] = "Created #{@data_group.name}"
|
|
16
|
+
redirect_to census_admin_path
|
|
17
|
+
else
|
|
18
|
+
render :action => 'new', :status => :unprocessable_entity
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def edit
|
|
23
|
+
@data_group = DataGroup.find(params[:id])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def update
|
|
27
|
+
@data_group = DataGroup.find(params[:id])
|
|
28
|
+
|
|
29
|
+
if @data_group.update_attributes(params[:data_group])
|
|
30
|
+
flash[:notice] = "Saved #{@data_group.name}"
|
|
31
|
+
redirect_to census_admin_path
|
|
32
|
+
else
|
|
33
|
+
render :action => 'edit', :status => :unprocessable_entity
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def destroy
|
|
38
|
+
@data_group = DataGroup.find(params[:id])
|
|
39
|
+
@data_group.destroy
|
|
40
|
+
flash[:notice] = "Deleted #{@data_group.name}"
|
|
41
|
+
redirect_to census_admin_path
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module CensusHelper
|
|
2
|
+
|
|
3
|
+
def link_to_remove_fields(name, form)
|
|
4
|
+
form.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def link_to_add_fields(name, form, association)
|
|
8
|
+
new_object = form.object.class.reflect_on_association(association).klass.new
|
|
9
|
+
fields = form.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
|
|
10
|
+
render(association.to_s.singularize + "_fields", :form => builder)
|
|
11
|
+
end
|
|
12
|
+
link_to_function(name, h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
class Answer < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
belongs_to :question
|
|
4
|
+
belongs_to :user
|
|
5
|
+
|
|
6
|
+
validates_presence_of :question,
|
|
7
|
+
:user
|
|
8
|
+
|
|
9
|
+
validate :ensure_valid_choice
|
|
10
|
+
validate :ensure_valid_data_type
|
|
11
|
+
validate :check_multiple_answers
|
|
12
|
+
|
|
13
|
+
named_scope :for_user, lambda { |user| { :conditions => {:user_id => user.id} } }
|
|
14
|
+
|
|
15
|
+
def formatted_data
|
|
16
|
+
question.format_data(self.data)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
question.to_s(self.data)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def ensure_valid_choice
|
|
28
|
+
return if question.blank? || data.blank?
|
|
29
|
+
errors.add_to_base("Invalid choice for #{question.prompt}") if question.restrict_values? && !question.choices.map(&:value).include?(self.data)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ensure_valid_data_type
|
|
33
|
+
return if question.blank? || data.blank?
|
|
34
|
+
message = question.validate_data(data)
|
|
35
|
+
errors.add_to_base("#{question.prompt} #{message}") if message
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def check_multiple_answers
|
|
39
|
+
return if question.blank? || user.blank?
|
|
40
|
+
errors.add_to_base("Only one answer allowed for #{question.prompt}") if new_record? && question.answers.for_user(user).size > 0 && !question.multiple?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class DataGroup < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
acts_as_list
|
|
4
|
+
|
|
5
|
+
has_many :questions, :dependent => :destroy, :inverse_of => :data_group
|
|
6
|
+
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:prompt].blank? }, :allow_destroy => true
|
|
7
|
+
|
|
8
|
+
validates_presence_of :name
|
|
9
|
+
|
|
10
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class Question < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
belongs_to :data_group, :inverse_of => :questions
|
|
4
|
+
acts_as_list :scope => :data_group
|
|
5
|
+
|
|
6
|
+
has_many :choices, :dependent => :destroy, :inverse_of => :question
|
|
7
|
+
accepts_nested_attributes_for :choices, :reject_if => lambda { |a| a[:value].blank? }, :allow_destroy => true
|
|
8
|
+
|
|
9
|
+
has_many :answers, :dependent => :destroy
|
|
10
|
+
|
|
11
|
+
validates_presence_of :prompt,
|
|
12
|
+
:data_group
|
|
13
|
+
|
|
14
|
+
def sql_transform(column_name = '?')
|
|
15
|
+
data_type_definition.sql_transform.call(column_name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def format_data(data)
|
|
19
|
+
data_type_definition.format_data.call(data)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def validate_data(data)
|
|
23
|
+
data_type_definition.validate_data.call(data)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_s(data)
|
|
27
|
+
format_data(data).to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def find_answers_matching(value)
|
|
31
|
+
answers.find(:all, :conditions => conditions_for(value), :include => :user)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def restrict_values?
|
|
35
|
+
choices.present? && !other?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def data_type_definition
|
|
43
|
+
Census::DataType.find(data_type) || Census::DataType.find('String')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def conditions_for(value)
|
|
47
|
+
if value.kind_of?(Range) || value.kind_of?(Array)
|
|
48
|
+
["#{sql_transform('data')} IN (?)", value]
|
|
49
|
+
else
|
|
50
|
+
["#{sql_transform('data')} = #{sql_transform}", value]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<% if question.choices.empty? -%>
|
|
2
|
+
<% answer = user.first_answer_for(question) -%>
|
|
3
|
+
<% fields_for "user[answers_attributes][#{user.answers.index(answer)}]", answer do |builder| -%>
|
|
4
|
+
<%= builder.hidden_field :id %>
|
|
5
|
+
<%= builder.hidden_field :question_id %>
|
|
6
|
+
<div class="text_field">
|
|
7
|
+
<%= builder.label :data, question.prompt %>
|
|
8
|
+
<%= builder.text_field :data %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end -%>
|
|
11
|
+
|
|
12
|
+
<% elsif question.multiple? -%>
|
|
13
|
+
<div class="checkboxes">
|
|
14
|
+
<%= label_tag question.prompt %>
|
|
15
|
+
<ul>
|
|
16
|
+
<% question.choices.each do |choice| -%>
|
|
17
|
+
<% answer = user.answer_for_choice(choice) -%>
|
|
18
|
+
<% fields_for "user[answers_attributes][#{user.answers.index(answer)}]", answer do |builder| -%>
|
|
19
|
+
<%= builder.hidden_field :id %>
|
|
20
|
+
<%= builder.hidden_field :question_id %>
|
|
21
|
+
<li>
|
|
22
|
+
<%= builder.check_box :data, {}, choice.value, '' %>
|
|
23
|
+
<%= builder.label :data, choice.value %>
|
|
24
|
+
</li>
|
|
25
|
+
<% end -%>
|
|
26
|
+
<% end -%>
|
|
27
|
+
</ul>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<% else -%>
|
|
31
|
+
<% answer = user.first_answer_for(question) -%>
|
|
32
|
+
<% fields_for "user[answers_attributes][#{user.answers.index(answer)}]", answer do |builder| -%>
|
|
33
|
+
<%= builder.hidden_field :id %>
|
|
34
|
+
<%= builder.hidden_field :question_id %>
|
|
35
|
+
<div class="select_field">
|
|
36
|
+
<%= builder.label :data, question.prompt %>
|
|
37
|
+
<%= builder.collection_select :data, question.choices, :value, :value, :include_blank => true %>
|
|
38
|
+
</div>
|
|
39
|
+
<% end -%>
|
|
40
|
+
<% end -%>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<div class="census_answers">
|
|
2
|
+
<% DataGroup.all.each do |group| -%>
|
|
3
|
+
<h3><%=h group.name %></h3>
|
|
4
|
+
<ul>
|
|
5
|
+
<% group.questions.each do |question| -%>
|
|
6
|
+
<li><b><%=h question.prompt %></b> <%=h user.all_answers_for(question).map(&:data).join(', ') %></li>
|
|
7
|
+
<% end -%>
|
|
8
|
+
</ul>
|
|
9
|
+
<% end -%>
|
|
10
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<div class="census_questions">
|
|
2
|
+
<% DataGroup.all.each do |group| -%>
|
|
3
|
+
<fieldset>
|
|
4
|
+
<legend><%=h group.name %></legend>
|
|
5
|
+
<% group.questions.each do |question| -%>
|
|
6
|
+
<%= render 'census/question_fields', :question => question, :user => user %>
|
|
7
|
+
<% end -%>
|
|
8
|
+
</fieldset>
|
|
9
|
+
<% end -%>
|
|
10
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%= form.error_messages %>
|
|
2
|
+
<div class="text_field">
|
|
3
|
+
<%= form.label :name, "Group Name" %>
|
|
4
|
+
<%= form.text_field :name %>
|
|
5
|
+
</div>
|
|
6
|
+
<% form.fields_for :questions do |builder| %>
|
|
7
|
+
<%= render "question_fields", :form => builder %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<div>
|
|
10
|
+
<%= link_to_add_fields "Add Question", form, :questions %>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<fieldset class="fields">
|
|
2
|
+
<legend>Question <%= form.object.position %></legend>
|
|
3
|
+
<div class="question">
|
|
4
|
+
<%= form.label :prompt, "Label" %>
|
|
5
|
+
<%= form.text_field :prompt %>
|
|
6
|
+
<%= link_to_remove_fields "remove", form %>
|
|
7
|
+
<br/>
|
|
8
|
+
<%= form.label :data_type %>
|
|
9
|
+
<%= form.collection_select :data_type, Census::DataType.all, :name, :name %>
|
|
10
|
+
</div>
|
|
11
|
+
<fieldset>
|
|
12
|
+
<legend>Answer Choices (leave empty to allow freeform text entry)</legend>
|
|
13
|
+
<% form.fields_for :choices do |builder| %>
|
|
14
|
+
<%= render 'choice_fields', :form => builder %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<div>
|
|
17
|
+
<%= link_to_add_fields "Add Answer", form, :choices %>
|
|
18
|
+
</div>
|
|
19
|
+
<%= form.check_box :multiple %>
|
|
20
|
+
<%= form.label :multiple, "Allow multiple selections" %>
|
|
21
|
+
</fieldset>
|
|
22
|
+
</fieldset>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<% form_for [:census, @data_group], :html => { :class => "census_data_group_form" } do |form| %>
|
|
2
|
+
<fieldset>
|
|
3
|
+
<legend>Edit Census Data Group</legend>
|
|
4
|
+
<%= render :partial => 'form', :object => form %>
|
|
5
|
+
<%= form.submit 'Save', :disable_with => 'Please wait...' %>
|
|
6
|
+
</fieldset>
|
|
7
|
+
<% end %>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<% form_for [:census, @data_group], :html => { :class => "census_data_group_form" } do |form| %>
|
|
2
|
+
<fieldset>
|
|
3
|
+
<legend>New Census Data Group</legend>
|
|
4
|
+
<%= render :partial => 'form', :object => form %>
|
|
5
|
+
<%= form.submit 'Save', :disable_with => 'Please wait...' %>
|
|
6
|
+
</fieldset>
|
|
7
|
+
<% end %>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
script/generate census
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/insert_commands.rb")
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/rake_commands.rb")
|
|
3
|
+
|
|
4
|
+
class CensusGenerator < Rails::Generator::Base
|
|
5
|
+
|
|
6
|
+
def manifest
|
|
7
|
+
record do |m|
|
|
8
|
+
m.directory File.join("config", "initializers")
|
|
9
|
+
m.file "census.rb", "config/initializers/census.rb"
|
|
10
|
+
|
|
11
|
+
m.directory File.join("public", "javascripts")
|
|
12
|
+
m.file "census.js", "public/javascripts/census.js"
|
|
13
|
+
|
|
14
|
+
user_model = "app/models/user.rb"
|
|
15
|
+
if File.exists?(user_model)
|
|
16
|
+
m.insert_into user_model, "include Census::User"
|
|
17
|
+
else
|
|
18
|
+
m.directory File.join("app", "models")
|
|
19
|
+
m.file "user.rb", user_model
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
m.directory File.join("test", "factories")
|
|
23
|
+
m.file "factories.rb", "test/factories/census.rb"
|
|
24
|
+
|
|
25
|
+
if ActiveRecord::Base.connection.table_exists?(:users)
|
|
26
|
+
m.migration_template "migrations/without_users.rb",
|
|
27
|
+
'db/migrate',
|
|
28
|
+
:migration_file_name => "create_census_tables"
|
|
29
|
+
else
|
|
30
|
+
m.migration_template "migrations/with_users.rb",
|
|
31
|
+
'db/migrate',
|
|
32
|
+
:migration_file_name => "create_census_tables"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
m.readme "README"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Mostly pinched from http://github.com/ryanb/nifty-generators/tree/master
|
|
2
|
+
|
|
3
|
+
Rails::Generator::Commands::Base.class_eval do
|
|
4
|
+
def file_contains?(relative_destination, line)
|
|
5
|
+
File.read(destination_path(relative_destination)).include?(line)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
Rails::Generator::Commands::Create.class_eval do
|
|
10
|
+
def insert_into(file, line)
|
|
11
|
+
logger.insert "#{line} into #{file}"
|
|
12
|
+
unless options[:pretend] || file_contains?(file, line)
|
|
13
|
+
gsub_file file, /^(class|module|.*Routes).*$/ do |match|
|
|
14
|
+
"#{match}\n #{line}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
Rails::Generator::Commands::Destroy.class_eval do
|
|
21
|
+
def insert_into(file, line)
|
|
22
|
+
logger.remove "#{line} from #{file}"
|
|
23
|
+
unless options[:pretend]
|
|
24
|
+
gsub_file file, "\n #{line}", ''
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Rails::Generator::Commands::List.class_eval do
|
|
30
|
+
def insert_into(file, line)
|
|
31
|
+
logger.insert "#{line} into #{file}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Rails::Generator::Commands::Create.class_eval do
|
|
2
|
+
def rake_db_migrate
|
|
3
|
+
logger.rake "db:migrate"
|
|
4
|
+
unless system("rake db:migrate")
|
|
5
|
+
logger.rake "db:migrate failed. Rolling back"
|
|
6
|
+
command(:destroy).invoke!
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Rails::Generator::Commands::Destroy.class_eval do
|
|
12
|
+
def rake_db_migrate
|
|
13
|
+
logger.rake "db:rollback"
|
|
14
|
+
system "rake db:rollback"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Rails::Generator::Commands::List.class_eval do
|
|
19
|
+
def rake_db_migrate
|
|
20
|
+
logger.rake "db:migrate"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
*******************************************************************************
|
|
3
|
+
|
|
4
|
+
Next:
|
|
5
|
+
|
|
6
|
+
1. In order for the question admin views to work, you'll need to include both
|
|
7
|
+
jQuery and the census.js file in your application layout:
|
|
8
|
+
|
|
9
|
+
<%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js' %>
|
|
10
|
+
<%= javascript_include_tag 'census' %>
|
|
11
|
+
|
|
12
|
+
2. Add a link to the question admin page somewhere in your app:
|
|
13
|
+
|
|
14
|
+
<%= link_to 'Set up questions', census_admin_path %>
|
|
15
|
+
|
|
16
|
+
3. Include the partial that displays answers in your user show page:
|
|
17
|
+
|
|
18
|
+
<%= render 'census/user_answers', :user => @user %>
|
|
19
|
+
|
|
20
|
+
4. Include the partial that allows the user to enter answers in your user
|
|
21
|
+
edit page:
|
|
22
|
+
|
|
23
|
+
<%= render 'census/user_questions', :user => @user %>
|
|
24
|
+
|
|
25
|
+
5. Migrate your database:
|
|
26
|
+
|
|
27
|
+
rake db:migrate
|
|
28
|
+
|
|
29
|
+
*******************************************************************************
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function remove_fields(link) {
|
|
2
|
+
$(link).prev("input[type=hidden]").val("1");
|
|
3
|
+
$(link).closest(".fields").hide();
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function add_fields(link, association, content) {
|
|
7
|
+
var new_id = new Date().getTime();
|
|
8
|
+
var regexp = new RegExp("new_" + association, "g")
|
|
9
|
+
$(link).parent().before(content.replace(regexp, new_id));
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Census::DataType.define("String")
|
|
2
|
+
|
|
3
|
+
Census::DataType.define(
|
|
4
|
+
"Number",
|
|
5
|
+
:sql_transform => lambda {|column_name| "CAST(#{column_name} AS SIGNED INTEGER)"},
|
|
6
|
+
:format_data => lambda {|data| data.to_i unless data.blank? },
|
|
7
|
+
:validate_data => lambda {|data| "must be a number" unless data =~ /^\d*$/}
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
Census::DataType.define(
|
|
11
|
+
"Yes/No",
|
|
12
|
+
:sql_transform => lambda {|column_name| "CAST(#{column_name} AS CHAR)"},
|
|
13
|
+
:format_data => lambda {|data| %w(1 T t Y y).include?(data) unless data.blank? }
|
|
14
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Factory.define :answer do |answer|
|
|
2
|
+
answer.association :question
|
|
3
|
+
answer.association :user
|
|
4
|
+
answer.data 'Factory Answer'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
Factory.define :choice do |choice|
|
|
8
|
+
choice.association :question
|
|
9
|
+
choice.value 'Factory Choice'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Factory.define :data_group do |group|
|
|
13
|
+
group.name 'Factory Data Group'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Factory.define :question do |question|
|
|
17
|
+
question.association :data_group
|
|
18
|
+
question.prompt 'Enter your response'
|
|
19
|
+
question.multiple false
|
|
20
|
+
question.other false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Factory.define :user do |user|
|
|
24
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class CreateCensusTables < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :data_groups do |t|
|
|
4
|
+
t.string :name
|
|
5
|
+
t.integer :position
|
|
6
|
+
t.timestamps
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
create_table :questions do |t|
|
|
10
|
+
t.integer :data_group_id
|
|
11
|
+
t.string :data_type
|
|
12
|
+
t.string :prompt
|
|
13
|
+
t.boolean :multiple
|
|
14
|
+
t.boolean :other
|
|
15
|
+
t.integer :position
|
|
16
|
+
t.timestamps
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
add_index :questions, :data_group_id
|
|
20
|
+
|
|
21
|
+
create_table :choices do |t|
|
|
22
|
+
t.integer :question_id
|
|
23
|
+
t.string :value
|
|
24
|
+
t.integer :position
|
|
25
|
+
t.timestamps
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
add_index :choices, :question_id
|
|
29
|
+
|
|
30
|
+
create_table(:users) do |t|
|
|
31
|
+
t.timestamps
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
create_table :answers do |t|
|
|
35
|
+
t.integer :question_id
|
|
36
|
+
t.integer :user_id
|
|
37
|
+
t.string :data
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
add_index :answers, :question_id
|
|
41
|
+
add_index :answers, :user_id
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.down
|
|
46
|
+
remove_index :answers, :question_id
|
|
47
|
+
remove_index :answers, :user_id
|
|
48
|
+
drop_table :answers
|
|
49
|
+
|
|
50
|
+
drop_table :users
|
|
51
|
+
|
|
52
|
+
remove_index :choices, :question_id
|
|
53
|
+
drop_table :choices
|
|
54
|
+
|
|
55
|
+
remove_index :questions, :data_group_id
|
|
56
|
+
drop_table :questions
|
|
57
|
+
|
|
58
|
+
drop_table :data_groups
|
|
59
|
+
end
|
|
60
|
+
end
|