census 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|