census 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -3,3 +3,110 @@
3
3
  Census is a Rails plugin that collects searchable demographics data for each
4
4
  of your application's users. The data to be collected is defined using a simple
5
5
  admin interface that Census provides.
6
+
7
+ == Setup
8
+
9
+ After installing the Census gem, require it in your Rails app and run the census
10
+ generator.
11
+
12
+ In your config/environment.rb:
13
+
14
+ config.gem 'census'
15
+
16
+ Run the generator and migrate your database:
17
+
18
+ script/generate census
19
+ rake db:migrate
20
+
21
+ == Configuration
22
+
23
+ The generator creates a sample configuration file in config/initializers/census.rb.
24
+ At the top of this file, you'll see a configuration option that allows you to
25
+ restrict access to the Census admin user interface. You'll probably want to set
26
+ this option, or anyone will be able to access the admin UI. Assuming your app has
27
+ an authentication system that implements a current_user method, and that your user
28
+ model has an admin? method, you could do something like this:
29
+
30
+ Census.configure do |config|
31
+ config.admin_role = 'current_user.admin?'
32
+ end
33
+
34
+ The remainder of the configuration file defines various data types that you can use
35
+ for the data you'll be collecting. Census comes with a few data types already
36
+ defined, and you can add additional types if needed. When defining a data type,
37
+ you can provide various Ruby procs that are used to convert the data to and from
38
+ a string representation that will be stored in the database. The procs you can
39
+ provide are:
40
+
41
+ * :sql_transform - returns a SQL fragment that will be used for comparing data when doing search queries
42
+
43
+ * :format_data - used to convert data from its string representation
44
+
45
+ * :validate_data - used to validate form field submissions, and should return nil if the data is valid or an error message if it is invalid
46
+
47
+ As an example, here's the data type definition for integer data:
48
+
49
+ Census::DataType.define(
50
+ "Number",
51
+ :sql_transform => lambda {|column_name| "CAST(#{column_name} AS SIGNED INTEGER)"},
52
+ :format_data => lambda {|data| data.to_i unless data.blank? },
53
+ :validate_data => lambda {|data| "must be a number" unless data =~ /^\d*$/}
54
+ )
55
+
56
+ == Defining Questions
57
+
58
+ You can access the Census admin UI at /census/admin. You may want to add a link
59
+ to census_admin_path somewhere in your app's administration interface. Using the
60
+ admin interface, you'll be able to create questions and their optional
61
+ multiple-choice answers. Questions are organized into data groups and can be
62
+ reordered using drag and drop.
63
+
64
+ You could also create DataGroup, Question, and Choice instances programatically
65
+ if you'd prefer not to use the admin UI.
66
+
67
+ == Allowing Users to Answer Your Questions
68
+
69
+ Census provides a partial that you can include in a form that collects answers
70
+ from your users. This partial assumes it's inside of a form_for(:user) block. It
71
+ will render fields for each of the questions you've defined.
72
+
73
+ <%= render 'census/user_answers', :user => @user %>
74
+
75
+ Data groups are rendered as fieldsets that contain a list of input fields, one
76
+ for each question. If you take a look at the rendered HTML, you'll see several
77
+ class and id attributes that you can use to style the form fields as needed.
78
+
79
+ == Displaying a User's Answers
80
+
81
+ Census provides a partial that you can use to display a user's answers.
82
+ Somewhere in your app, probably in users/show.html.erb, add the following
83
+ to render the partial:
84
+
85
+ <%= render 'census/user_answers', :user => @user %>
86
+
87
+ == Searching
88
+
89
+ Census provides a search interface for finding users whose answers match a list
90
+ of search criteria. To perform a search, first create a Census::Search object,
91
+ passing your search criteria as a hash of questions and values. We'll assume
92
+ for this example that we have questions for "Hair Color" and "Age," and
93
+ we'll look them up by name.
94
+
95
+ hair_color = Question.find_by_prompt('Hair Color')
96
+ age = Question.find_by_prompt('Age')
97
+ search = Census::Search.new(hair_color => 'Brown', age => 25)
98
+
99
+ The search listed above will find all users who have brown hair and are 25 years
100
+ old. You can also pass arrays or ranges, like this:
101
+
102
+ search = Census::Search.new(hair_color => ['Brown', 'Blond'], age => 25..30)
103
+
104
+ That search will find all users between the ages of 25 and 30 that have either
105
+ brown or blond hair. Once you've created the Search object, call its perform
106
+ method to query the database and get back the list of matching users.
107
+
108
+ users = search.perform
109
+
110
+ == Copyright
111
+
112
+ Copyright (c) 2010 Envy Labs LLC. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
@@ -1,7 +1,9 @@
1
1
  class Census::DataGroupsController < ApplicationController
2
2
 
3
+ before_filter :restrict_access
4
+
3
5
  def index
4
- @data_groups = DataGroup.all(:order => :position)
6
+ @data_groups = DataGroup.all
5
7
  end
6
8
 
7
9
  def new
@@ -40,5 +42,22 @@ class Census::DataGroupsController < ApplicationController
40
42
  flash[:notice] = "Deleted #{@data_group.name}"
41
43
  redirect_to census_admin_path
42
44
  end
45
+
46
+ def sort
47
+ group_positions = params[:data_group].to_a
48
+ DataGroup.all.each_with_index do |group, i|
49
+ group.position = group_positions.index(group.id.to_s) + 1
50
+ group.save
51
+ end
52
+ render :text => 'ok'
53
+ end
54
+
55
+
56
+ private
57
+
58
+
59
+ def restrict_access
60
+ render :text => 'Not authorized', :status => :unauthorized unless instance_eval(Census::configuration.admin_role.to_s)
61
+ end
43
62
 
44
63
  end
data/app/models/choice.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  class Choice < ActiveRecord::Base
2
2
 
3
3
  belongs_to :question, :inverse_of => :choices
4
- acts_as_list :scope => :question
4
+ default_scope :order => :position
5
5
 
6
6
  validates_presence_of :value,
7
7
  :question
@@ -1,6 +1,7 @@
1
1
  class DataGroup < ActiveRecord::Base
2
2
 
3
3
  acts_as_list
4
+ default_scope :order => :position
4
5
 
5
6
  has_many :questions, :dependent => :destroy, :inverse_of => :data_group
6
7
  accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:prompt].blank? }, :allow_destroy => true
@@ -1,7 +1,7 @@
1
1
  class Question < ActiveRecord::Base
2
2
 
3
3
  belongs_to :data_group, :inverse_of => :questions
4
- acts_as_list :scope => :data_group
4
+ default_scope :order => :position
5
5
 
6
6
  has_many :choices, :dependent => :destroy, :inverse_of => :question
7
7
  accepts_nested_attributes_for :choices, :reject_if => lambda { |a| a[:value].blank? }, :allow_destroy => true
@@ -1,4 +1,5 @@
1
- <div class="fields">
1
+ <div class="census_choice fields" id="choice-<%= form.object.id %>">
2
+ <%= form.hidden_field :position, :class => 'choice_position' %>
2
3
  <%= form.text_field :value %>
3
4
  <%= link_to_remove_fields "remove", form %>
4
5
  </div>
@@ -2,10 +2,13 @@
2
2
  <div class="text_field">
3
3
  <%= form.label :name, "Group Name" %>
4
4
  <%= form.text_field :name %>
5
+ <label><span>Drag and drop questions and answer choices to rearrange them</span></label>
5
6
  </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 %>
7
+ <div class="census_question_list" id="<%= form.object.id %>">
8
+ <% form.fields_for :questions do |builder| %>
9
+ <%= render "question_fields", :form => builder %>
10
+ <% end %>
11
+ <p>
12
+ <%= link_to_add_fields "Add Question", form, :questions %>
13
+ </p>
11
14
  </div>
@@ -1,22 +1,24 @@
1
- <fieldset class="fields">
2
- <legend>Question <%= form.object.position %></legend>
1
+ <fieldset class="census_question fields" id="question-<%= form.object.id %>">
3
2
  <div class="question">
4
- <%= form.label :prompt, "Label" %>
3
+ <%= form.hidden_field :position, :class => 'question_position' %>
4
+ <%= form.label :prompt, "Question" %>
5
5
  <%= form.text_field :prompt %>
6
6
  <%= link_to_remove_fields "remove", form %>
7
7
  <br/>
8
8
  <%= form.label :data_type %>
9
9
  <%= form.collection_select :data_type, Census::DataType.all, :name, :name %>
10
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 %>
11
+ <label>Answer Choices <span>Leave empty to allow freeform text entry</span></label>
12
+ <fieldset class="choices">
13
+ <div class="census_choice_list" id="<%= form.object.id %>">
14
+ <% form.fields_for :choices do |builder| %>
15
+ <%= render 'choice_fields', :form => builder %>
16
+ <% end %>
17
+ <div>
18
+ <%= link_to_add_fields "Add Answer", form, :choices %>
19
+ <%= form.check_box :multiple %>
20
+ <%= form.label :multiple, "Allow multiple selections" %>
21
+ </div>
18
22
  </div>
19
- <%= form.check_box :multiple %>
20
- <%= form.label :multiple, "Allow multiple selections" %>
21
23
  </fieldset>
22
24
  </fieldset>
@@ -1,8 +1,9 @@
1
1
  <h2>Census Data Groups</h2>
2
2
  <ul class="census_data_group_list">
3
3
  <% @data_groups.each do |group| %>
4
- <li>
5
- <%=link_to group.name, edit_census_data_group_path(group) %>
4
+ <li class="census_data_group" id="data_group-<%= group.id %>">
5
+ <%=h group.name %>
6
+ <%=link_to 'edit', edit_census_data_group_path(group) %>
6
7
  </li>
7
8
  <% end %>
8
9
  </ul>
data/config/routes.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  ActionController::Routing::Routes.draw do |map|
2
2
 
3
3
  map.namespace :census do |census|
4
- census.resources :data_groups, :except => [:index, :show]
4
+ census.resources :data_groups,
5
+ :except => [:index, :show],
6
+ :collection => {:sort => :put}
7
+
5
8
  census.admin 'admin', :controller => 'data_groups', :action => 'index'
6
9
  end
7
10
 
@@ -10,6 +10,9 @@ class CensusGenerator < Rails::Generator::Base
10
10
 
11
11
  m.directory File.join("public", "javascripts")
12
12
  m.file "census.js", "public/javascripts/census.js"
13
+
14
+ m.directory File.join("public", "stylesheets")
15
+ m.file "census.css", "public/stylesheets/census.css"
13
16
 
14
17
  user_model = "app/models/user.rb"
15
18
  if File.exists?(user_model)
@@ -4,25 +4,33 @@
4
4
  Next:
5
5
 
6
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:
7
+ jQuery and the census.js file in your application layout. To enable drag-and-drop
8
+ sorting of questions and choices in the census admin, you'll also need to
9
+ include jQuery UI.
8
10
 
9
- <%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js' %>
11
+ <%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js' %>
12
+ <%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js' %>
10
13
  <%= javascript_include_tag 'census' %>
11
14
 
12
- 2. Add a link to the question admin page somewhere in your app:
15
+ 2. If you'd like the Census admin pages to look nicer, include the provided census.css
16
+ file in your application layout.
17
+
18
+ <%= stylesheet_link_tag 'census' %>
19
+
20
+ 3. Add a link to the question admin page somewhere in your app:
13
21
 
14
22
  <%= link_to 'Set up questions', census_admin_path %>
15
23
 
16
- 3. Include the partial that displays answers in your user show page:
24
+ 4. Include the partial that displays answers in your user show page:
17
25
 
18
26
  <%= render 'census/user_answers', :user => @user %>
19
27
 
20
- 4. Include the partial that allows the user to enter answers in your user
28
+ 5. Include the partial that allows the user to enter answers in your user
21
29
  edit page:
22
30
 
23
31
  <%= render 'census/user_questions', :user => @user %>
24
32
 
25
- 5. Migrate your database:
33
+ 6. Migrate your database:
26
34
 
27
35
  rake db:migrate
28
36
 
@@ -0,0 +1,71 @@
1
+ .census_data_group_list {
2
+ font: 12pt sans-serif;
3
+ list-style: none;
4
+ }
5
+
6
+ .census_data_group_list li {
7
+ padding: 1px 0px;
8
+ }
9
+
10
+ .census_data_group_list a {
11
+ font-size: 0.9em;
12
+ }
13
+
14
+ .census_data_group_form {
15
+ font: 10pt sans-serif;
16
+ }
17
+
18
+ .census_data_group_form label {
19
+ display: inline-block;
20
+ margin-top: 5px;
21
+ margin-left: 10px;
22
+ }
23
+
24
+ .census_data_group_form label span {
25
+ margin-left: 20px;
26
+ font-size: 0.9em;
27
+ color: #777;
28
+ }
29
+
30
+ .census_data_group_form fieldset {
31
+ background: #fff;
32
+ border: none;
33
+ -moz-border-radius: 5px;
34
+ -webkit-border-radius: 5px;
35
+ }
36
+
37
+ .census_data_group_form fieldset legend {
38
+ padding: 30px 0px 5px;
39
+ margin: 0px;
40
+ font-size: 1.2em;
41
+ }
42
+
43
+ .census_data_group_form .census_question {
44
+ margin-top: 20px;
45
+ padding: 10px 8px;
46
+ background: #ddd;
47
+ -moz-border-radius: 10px;
48
+ -webkit-border-radius: 10px;
49
+ }
50
+
51
+ .census_data_group_form .census_question .choices {
52
+ font-size: 0.8em;
53
+ margin-top: 5px;
54
+ padding-top: 10px;
55
+ }
56
+
57
+ .census_data_group_form .census_choice {
58
+ padding: 5px;
59
+ margin-bottom: 5px;
60
+ background: #ccc;
61
+ -moz-border-radius: 5px;
62
+ -webkit-border-radius: 5px;
63
+ }
64
+
65
+ .census_data_group_form .census_question .choices label {
66
+ margin-left: 0px;
67
+ }
68
+
69
+ .census_data_group_form .census_question .choices a {
70
+ margin: 0px 20px 0px 2px;
71
+ }
@@ -1,10 +1,47 @@
1
+ jQuery.ajaxSetup({
2
+ 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
3
+ })
4
+
1
5
  function remove_fields(link) {
2
6
  $(link).prev("input[type=hidden]").val("1");
3
7
  $(link).closest(".fields").hide();
8
+ update_positions();
4
9
  }
5
10
 
6
11
  function add_fields(link, association, content) {
7
12
  var new_id = new Date().getTime();
8
13
  var regexp = new RegExp("new_" + association, "g")
9
14
  $(link).parent().before(content.replace(regexp, new_id));
15
+ $('.census_question_list').sortable('refresh');
16
+ $('.census_choice_list').sortable('refresh');
17
+
18
+ if (association == "questions") {
19
+ $('.census_choice_list').sortable({items:'.census_choice', containment:'parent', axis:'y', update: function() {
20
+ update_positions();
21
+ }});
22
+ }
23
+
24
+ update_positions();
25
+ }
26
+
27
+ function update_positions() {
28
+ $('.census_question').each(function(index) {
29
+ $(this).find('.question_position').val(index + 1);
30
+ $(this).find('.census_choice').each(function(index) {
31
+ $(this).find('.choice_position').val(index + 1);
32
+ });
33
+ });
10
34
  }
35
+
36
+ $(function() {
37
+ $('.census_data_group_list').sortable({items:'.census_data_group', containment:'parent', axis:'y', update: function() {
38
+ $.post('/census/data_groups/sort', '_method=put&'+$(this).sortable('serialize'));
39
+ }});
40
+ $('.census_question_list').sortable({items:'.census_question', containment:'parent', axis:'y', update: function() {
41
+ update_positions();
42
+ }});
43
+ $('.census_choice_list').sortable({items:'.census_choice', containment:'parent', axis:'y', update: function() {
44
+ update_positions();
45
+ }});
46
+ update_positions();
47
+ })
@@ -1,3 +1,22 @@
1
+ Census.configure do |config|
2
+ # To restrict access to the census admin UI, specify a code snippet that
3
+ # evaluates to true for anyone who should have access. By default, everyone
4
+ # has access to the admin UI.
5
+ #
6
+ # config.admin_role = 'current_user.admin?'
7
+ end
8
+
9
+ #
10
+ # Define data types. All data is stored in the database as strings, and you can
11
+ # provide procs that will be used to convert from the stored strings to any data
12
+ # type you need.
13
+ #
14
+ # :sql_transform - should return a SQL fragment that will be used for comparing
15
+ # data when doing search queries
16
+ # :format_data - is used to convert data from its string representation
17
+ # :validate_data - is used to validate form field submissions, and should return
18
+ # nil if the data is valid and an error message if it is invalid
19
+ #
1
20
  Census::DataType.define("String")
2
21
 
3
22
  Census::DataType.define(
@@ -6,9 +25,3 @@ Census::DataType.define(
6
25
  :format_data => lambda {|data| data.to_i unless data.blank? },
7
26
  :validate_data => lambda {|data| "must be a number" unless data =~ /^\d*$/}
8
27
  )
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,25 @@
1
+ module Census
2
+ class Configuration
3
+ attr_accessor :admin_role
4
+
5
+ def initialize
6
+ @admin_role = true
7
+ end
8
+ end
9
+
10
+ class << self
11
+ attr_accessor :configuration
12
+ end
13
+
14
+ # Configure Census someplace sensible,
15
+ # like config/initializers/census.rb
16
+ #
17
+ # @example
18
+ # Census.configure do |config|
19
+ # config.admin_role = 'current_user.admin?'
20
+ # end
21
+ def self.configure
22
+ self.configuration ||= Configuration.new
23
+ yield(configuration)
24
+ end
25
+ end
data/lib/census.rb CHANGED
@@ -1 +1,4 @@
1
+ require 'census/configuration'
2
+ require 'census/data_type'
1
3
  require 'census/user'
4
+ require 'census/search'
@@ -22,6 +22,9 @@ class DataGroupsControllerTest < ActionController::TestCase
22
22
  should_route :delete, '/census/data_groups/1',
23
23
  :controller => 'census/data_groups', :action => 'destroy', :id => '1'
24
24
 
25
+ should_route :put, '/census/data_groups/sort',
26
+ :controller => 'census/data_groups', :action => 'sort'
27
+
25
28
  context 'The Census::DataGroupsController' do
26
29
 
27
30
  context 'using GET to index' do
@@ -37,6 +40,25 @@ class DataGroupsControllerTest < ActionController::TestCase
37
40
  should_assign_to :data_groups
38
41
 
39
42
  end
43
+
44
+ context 'using GET to index with restricted access' do
45
+
46
+ setup do
47
+ Census.configure do |config|
48
+ config.admin_role = false
49
+ end
50
+ get :index
51
+ end
52
+
53
+ teardown do
54
+ Census.configure do |config|
55
+ config.admin_role = true
56
+ end
57
+ end
58
+
59
+ should_respond_with :unauthorized
60
+
61
+ end
40
62
 
41
63
  context 'using GET to new' do
42
64
 
@@ -159,6 +181,26 @@ class DataGroupsControllerTest < ActionController::TestCase
159
181
  end
160
182
 
161
183
  end
184
+
185
+ context 'using PUT to sort' do
186
+
187
+ setup do
188
+ @group_a = Factory(:data_group, :position => 1)
189
+ @group_b = Factory(:data_group, :position => 2)
190
+ @group_c = Factory(:data_group, :position => 3)
191
+ put :sort, :data_group => [@group_b.id.to_s, @group_a.id.to_s, @group_c.id.to_s]
192
+ end
193
+
194
+ should_respond_with :success
195
+ should_respond_with_content_type :html
196
+
197
+ should 'rearrange the data groups' do
198
+ assert_equal @group_b, DataGroup.all[0]
199
+ assert_equal @group_a, DataGroup.all[1]
200
+ assert_equal @group_c, DataGroup.all[2]
201
+ end
202
+
203
+ end
162
204
 
163
205
  end
164
206
 
@@ -12,8 +12,6 @@ class ChoiceTest < ActiveSupport::TestCase
12
12
 
13
13
  should_belong_to :question
14
14
 
15
- should_act_as_list
16
-
17
15
  should_validate_presence_of :value,
18
16
  :question
19
17
 
@@ -14,8 +14,6 @@ class QuestionTest < ActiveSupport::TestCase
14
14
  should_have_many :choices, :dependent => :destroy
15
15
  should_have_many :answers, :dependent => :destroy
16
16
 
17
- should_act_as_list
18
-
19
17
  should_validate_presence_of :prompt,
20
18
  :data_group
21
19
 
@@ -1,3 +1,11 @@
1
+ Census.configure do |config|
2
+ # To restrict access to the census admin UI, specify a code snippet that
3
+ # evaluates to true for anyone who should have access. By default, everyone
4
+ # has access to the admin UI.
5
+ #
6
+ # config.admin_role = 'current_user.admin?'
7
+ end
8
+
1
9
  Census::DataType.define("String")
2
10
 
3
11
  Census::DataType.define(
@@ -9,7 +9,7 @@
9
9
  #
10
10
  # It's strongly recommended to check this file into your version control system.
11
11
 
12
- ActiveRecord::Schema.define(:version => 20100408172932) do
12
+ ActiveRecord::Schema.define(:version => 20100416173354) do
13
13
 
14
14
  create_table "answers", :force => true do |t|
15
15
  t.integer "question_id"
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
8
- - 1
9
- version: 0.3.1
7
+ - 4
8
+ - 0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mark Kendall
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-08 00:00:00 -04:00
17
+ date: 2010-04-16 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -104,6 +104,7 @@ files:
104
104
  - generators/census/lib/insert_commands.rb
105
105
  - generators/census/lib/rake_commands.rb
106
106
  - generators/census/templates/README
107
+ - generators/census/templates/census.css
107
108
  - generators/census/templates/census.js
108
109
  - generators/census/templates/census.rb
109
110
  - generators/census/templates/factories.rb
@@ -111,6 +112,7 @@ files:
111
112
  - generators/census/templates/migrations/without_users.rb
112
113
  - generators/census/templates/user.rb
113
114
  - lib/census.rb
115
+ - lib/census/configuration.rb
114
116
  - lib/census/data_type.rb
115
117
  - lib/census/search.rb
116
118
  - lib/census/user.rb
@@ -169,7 +171,7 @@ test_files:
169
171
  - test/rails_root/config/initializers/new_rails_defaults.rb
170
172
  - test/rails_root/config/initializers/session_store.rb
171
173
  - test/rails_root/config/routes.rb
172
- - test/rails_root/db/migrate/20100408172932_create_census_tables.rb
174
+ - test/rails_root/db/migrate/20100416173354_create_census_tables.rb
173
175
  - test/rails_root/db/schema.rb
174
176
  - test/rails_root/test/factories/census.rb
175
177
  - test/rails_root/test/performance/browsing_test.rb