turkee 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +25 -8
- data/lib/generators/turkee/templates/add_hit_duration.rb.erb +15 -0
- data/lib/generators/turkee/templates/add_imported_assignment_details.rb.erb +33 -0
- data/lib/generators/turkee/turkee_generator.rb +8 -0
- data/lib/tasks/turkee.rb +1 -1
- data/lib/turkee.rb +28 -14
- data/spec/spec_helper.rb +1 -0
- metadata +19 -17
data/README.rdoc
CHANGED
@@ -74,7 +74,7 @@ Inside the config/initializers directory, you'll see the file turkee.rb. Edit t
|
|
74
74
|
|
75
75
|
3) Change your forms to use the form helper.
|
76
76
|
|
77
|
-
|
77
|
+
<%= turkee_form_for(@survey, params) do |f| %>
|
78
78
|
<p><%= f.text_area :value, :disabled => @disabled %></p>
|
79
79
|
<p><%= f.submit 'Create', :disabled => @disabled %></p>
|
80
80
|
<% end %>
|
@@ -93,7 +93,7 @@ Using the turkee_form_for helper will post the form to the Mechanical Turk sandb
|
|
93
93
|
rake turkee:post_hit[<Host>, <Title>, <Description>, <Model>, <Number of Assignments>, <Reward>, <Lifetime>]
|
94
94
|
|
95
95
|
e.g. :
|
96
|
-
rake turkee:post_hit["https://www.yourapp.com","Please complete our survey","Tell us your favorite color.","Survey",100,0.05,
|
96
|
+
rake turkee:post_hit["https://www.yourapp.com","Please complete our survey","Tell us your favorite color.","Survey",100,0.05,5,1]
|
97
97
|
** Do not put spaces before or after commas for the rake task parameters
|
98
98
|
|
99
99
|
This will insert a row for the requested HIT into the turkee_tasks table. The turkee_tasks entry stores (along with the other properties) the HIT URL (e.g. http://workersandbox.mturk.com/mturk/preview?groupId=1HGHJJGHQSJB7WMWJ33YS8WM169XNIL ) and HIT ID (e.g. 1J1EXO8SUQ3URTTUYGHJ7EKUT11 ). These values are returned from Mechanical Turk when the HIT request is posted.
|
@@ -103,7 +103,7 @@ When a Turk worker views your HIT, the HIT will display your form within an iFra
|
|
103
103
|
5) Allow some time for the Mechanical Turk workers ("Turkers") to respond to your HIT.
|
104
104
|
|
105
105
|
6) Run the rake task that retrieves the values from Mechanical Turk and stores the user entered values into your model.
|
106
|
-
rake turkee
|
106
|
+
rake turkee:get_all_results
|
107
107
|
|
108
108
|
Rerun this task periodically to retrieve newly entered form values. You can setup this task as a cronjob to automate this.
|
109
109
|
|
@@ -124,18 +124,35 @@ As for Mechanical Turk approval, if the row is created and you haven't specified
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
+
8) When all specified assignments for a HIT have been completed, Turkee will attempt to call the optional hit_complete class method for the model. This can be used for any cleanup logic. E.g. :
|
128
|
+
class Survey < ActiveRecord::Base
|
129
|
+
def self.hit_complete(turkee_task)
|
130
|
+
#do something
|
131
|
+
end
|
132
|
+
end
|
127
133
|
|
128
134
|
== Advanced Usage
|
129
135
|
|
130
|
-
You can use the params hash to pass object IDs to your forms. E.g. if you wanted to setup a form of questions about a given URL (let's call the model UrlSurvey), your code would look something like :
|
136
|
+
1) You can use the params hash to pass object IDs to your forms. E.g. if you wanted to setup a form of questions about a given URL (let's call the model UrlSurvey), your code would look something like :
|
131
137
|
|
132
|
-
URL.all do |url|
|
133
|
-
|
134
|
-
|
135
|
-
end
|
138
|
+
URL.all do |url|
|
139
|
+
Turkee::TurkeeTask.create_hit(host, hit_title, hit_description, UrlSurvey, num_assignments, reward,
|
140
|
+
lifetime, duration, {}, {:url_id => url.id}, {})
|
141
|
+
end
|
136
142
|
|
137
143
|
Then when displaying your form, you can find the URL object via the params[:url_id] value.
|
138
144
|
|
145
|
+
|
146
|
+
2) Turkee assumes that the form url will be the new action for the class passed to create_hit. If you have a more complex form url which would be the case for nested resources, you can use the :form_url
|
147
|
+
option to designate a form url different from the default.
|
148
|
+
|
149
|
+
|
150
|
+
form_url = Rails.application.routes.url_helpers.send("new_user_survey_path",@my_survey)
|
151
|
+
|
152
|
+
Turkee::TurkeeTask.create_hit(host, hit_title, hit_description, :Survey, num_assignments, reward,
|
153
|
+
lifetime, duration, {}, {}, {:form_url => form_url})
|
154
|
+
|
155
|
+
|
139
156
|
== Gotchas
|
140
157
|
|
141
158
|
1) The application that hosts your external forms preferably should have an https interface (you're going to have to buy an SSL certificate). If the forms are hosted on an unsecured host (http), because Mechanical Turk defaults to https, you're going to receive the ugly popup from IE regarding "mixed content" (http://msdn.microsoft.com/en-us/library/ee264315%28v=vs.85%29.aspx).
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class AddHitDuration < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
unless column_exists? :turkee_tasks, :hit_duration
|
5
|
+
add_column :turkee_tasks, :hit_duration, :integer
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
if column_exists? :turkee_tasks, :hit_duration
|
11
|
+
remove_column :turkee_tasks, :hit_duration
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class AddImportedAssignmentDetails < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
unless column_exists? :turkee_imported_assignments, :turkee_task_id
|
5
|
+
add_column :turkee_imported_assignments, :turkee_task_id, :integer
|
6
|
+
add_index :turkee_imported_assignments, :turkee_task_id, :unique => false
|
7
|
+
end
|
8
|
+
|
9
|
+
unless column_exists? :turkee_imported_assignments, :worker_id
|
10
|
+
add_column :turkee_imported_assignments, :worker_id, :string
|
11
|
+
end
|
12
|
+
|
13
|
+
unless column_exists? :turkee_imported_assignments, :result_id
|
14
|
+
add_column :turkee_imported_assignments, :result_id, :integer
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
if column_exists? :turkee_imported_assignments, :turkee_task_id
|
20
|
+
remove_column :turkee_imported_assignments, :turkee_task_id
|
21
|
+
remove_index :turkee_imported_assignments, :turkee_task_id
|
22
|
+
end
|
23
|
+
|
24
|
+
if column_exists? :turkee_imported_assignments, :worker_id
|
25
|
+
remove_column :turkee_imported_assignments, :worker_id
|
26
|
+
end
|
27
|
+
|
28
|
+
if column_exists? :turkee_imported_assignments, :result_id
|
29
|
+
remove_column :turkee_imported_assignments, :result_id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -25,6 +25,14 @@ class TurkeeGenerator < Rails::Generators::Base
|
|
25
25
|
sleep 1
|
26
26
|
|
27
27
|
migration_template "add_completed_tasks.rb.erb", "db/migrate/add_completed_tasks.rb"
|
28
|
+
|
29
|
+
sleep 1
|
30
|
+
|
31
|
+
migration_template "add_imported_assignment_details.rb.erb", "db/migrate/add_imported_assignment_details.rb"
|
32
|
+
|
33
|
+
sleep 1
|
34
|
+
|
35
|
+
migration_template "add_hit_duration.rb.erb", "db/migrate/add_hit_duration.rb"
|
28
36
|
|
29
37
|
end
|
30
38
|
|
data/lib/tasks/turkee.rb
CHANGED
@@ -2,7 +2,7 @@ require 'rake'
|
|
2
2
|
require 'turkee'
|
3
3
|
|
4
4
|
namespace :turkee do
|
5
|
-
desc "Post your form to Mechanical Turk (HIT). Task takes the application's host URL, HIT title, HIT description, model name, number of responses, reward for each response,
|
5
|
+
desc "Post your form to Mechanical Turk (HIT). Task takes the application's host URL, HIT title, HIT description, model name, number of responses, reward for each response, number of days the HIT should be valid, and number of hours a worker has to complete the HIT."
|
6
6
|
task :post_hit, [:host, :title, :description, :model, :num_assignments, :reward, :lifetime] => :environment do |t, args|
|
7
7
|
hit = Turkee::TurkeeTask.create_hit(args[:host],args[:title], args[:description], args[:model],
|
8
8
|
args[:num_assignments], args[:reward], args[:lifetime])
|
data/lib/turkee.rb
CHANGED
@@ -11,15 +11,16 @@ module Turkee
|
|
11
11
|
|
12
12
|
# Model simply tracks what assignments have been imported
|
13
13
|
class TurkeeImportedAssignment < ActiveRecord::Base
|
14
|
+
attr_accessible :assignment_id, :turkee_task_id, :worker_id, :result_id
|
14
15
|
end
|
15
16
|
|
16
17
|
class TurkeeTask < ActiveRecord::Base
|
17
|
-
attr_accessible :sandbox, :hit_title, :hit_description, :hit_reward, :hit_num_assignments, :hit_lifetime,
|
18
|
+
attr_accessible :sandbox, :hit_title, :hit_description, :hit_reward, :hit_num_assignments, :hit_lifetime, :hit_duration,
|
18
19
|
:form_url, :hit_url, :hit_id, :task_type, :complete
|
19
20
|
|
20
21
|
HIT_FRAMEHEIGHT = 1000
|
21
22
|
|
22
|
-
scope :unprocessed_hits,
|
23
|
+
scope :unprocessed_hits, lambda{ where('complete = ? AND sandbox = ?', false, RTurk.sandbox?) }
|
23
24
|
|
24
25
|
# Use this method to go out and retrieve the data for all of the posted Turk Tasks.
|
25
26
|
# Each specific TurkeeTask object (determined by task_type field) is in charge of
|
@@ -35,7 +36,7 @@ module Turkee
|
|
35
36
|
turks.each do |turk|
|
36
37
|
hit = RTurk::Hit.new(turk.hit_id)
|
37
38
|
|
38
|
-
models =
|
39
|
+
models = Set.new
|
39
40
|
hit.assignments.each do |assignment|
|
40
41
|
next unless submitted?(assignment.status)
|
41
42
|
next unless TurkeeImportedAssignment.find_by_assignment_id(assignment.id).nil?
|
@@ -45,14 +46,16 @@ module Turkee
|
|
45
46
|
model = find_model(param_hash)
|
46
47
|
|
47
48
|
next if model.nil?
|
48
|
-
|
49
|
+
models << model
|
50
|
+
|
51
|
+
logger.debug "param_hash = #{param_hash}"
|
49
52
|
result = model.create(param_hash[model.to_s.underscore])
|
50
53
|
|
51
54
|
# If there's a custom approve? method, see if we should approve the submitted assignment
|
52
55
|
# otherwise just approve it by default
|
53
56
|
process_result(assignment, result, turk)
|
54
57
|
|
55
|
-
TurkeeImportedAssignment.create(:assignment_id => assignment.id
|
58
|
+
TurkeeImportedAssignment.create!(:assignment_id => assignment.id, :turkee_task_id => turk.id, :worker_id => assignment.worker_id, :result_id => result.id)
|
56
59
|
end
|
57
60
|
|
58
61
|
check_hit_completeness(hit, turk, models)
|
@@ -65,17 +68,16 @@ module Turkee
|
|
65
68
|
end
|
66
69
|
|
67
70
|
# Creates a new Mechanical Turk task on AMZN with the given title, desc, etc
|
68
|
-
def self.create_hit(host, hit_title, hit_description, typ, num_assignments, reward, lifetime, qualifications = {}, params = {}, opts = {})
|
69
|
-
|
71
|
+
def self.create_hit(host, hit_title, hit_description, typ, num_assignments, reward, lifetime, duration = nil, qualifications = {}, params = {}, opts = {})
|
70
72
|
model = Object::const_get(typ)
|
71
|
-
|
72
|
-
f_url = (full_url(opts[:form_url], params) || form_url(host, model, params))
|
73
|
+
f_url = build_url(host, model, params, opts)
|
73
74
|
|
74
75
|
h = RTurk::Hit.create(:title => hit_title) do |hit|
|
75
76
|
hit.assignments = num_assignments
|
76
77
|
hit.description = hit_description
|
77
78
|
hit.reward = reward
|
78
|
-
hit.lifetime =
|
79
|
+
hit.lifetime = lifetime.to_i.days.seconds.to_i
|
80
|
+
hit.duration = duration.to_i.hours.seconds.to_i if duration
|
79
81
|
hit.question(f_url, :frame_height => HIT_FRAMEHEIGHT)
|
80
82
|
unless qualifications.empty?
|
81
83
|
qualifications.each do |key, value|
|
@@ -87,9 +89,10 @@ module Turkee
|
|
87
89
|
TurkeeTask.create(:sandbox => RTurk.sandbox?,
|
88
90
|
:hit_title => hit_title, :hit_description => hit_description,
|
89
91
|
:hit_reward => reward.to_f, :hit_num_assignments => num_assignments.to_i,
|
90
|
-
:hit_lifetime => lifetime, :
|
91
|
-
:
|
92
|
-
:task_type => typ,
|
92
|
+
:hit_lifetime => lifetime, :hit_duration => duration,
|
93
|
+
:form_url => f_url, :hit_url => h.url,
|
94
|
+
:hit_id => h.id, :task_type => typ,
|
95
|
+
:complete => false)
|
93
96
|
|
94
97
|
end
|
95
98
|
|
@@ -140,7 +143,7 @@ module Turkee
|
|
140
143
|
end
|
141
144
|
|
142
145
|
def self.check_hit_completeness(hit, turk, models)
|
143
|
-
|
146
|
+
logger.debug "#### turk.completed_assignments == turk.hit_num_assignments :: #{turk.completed_assignments} == #{turk.hit_num_assignments}"
|
144
147
|
if turk.completed_assignments == turk.hit_num_assignments
|
145
148
|
hit.dispose!
|
146
149
|
turk.complete = true
|
@@ -197,13 +200,24 @@ module Turkee
|
|
197
200
|
end
|
198
201
|
nil
|
199
202
|
end
|
203
|
+
|
204
|
+
# Returns custom URL if opts[:form_url] is specified. Otherwise, builds the default url from the model's :new route
|
205
|
+
def self.build_url(host, model, params, opts)
|
206
|
+
if opts[:form_url]
|
207
|
+
full_url(opts[:form_url], params)
|
208
|
+
else
|
209
|
+
form_url(host, model, params)
|
210
|
+
end
|
211
|
+
end
|
200
212
|
|
213
|
+
# Returns the default url of the model's :new route
|
201
214
|
def self.form_url(host, typ, params = {})
|
202
215
|
@app ||= ActionController::Integration::Session.new(Rails.application)
|
203
216
|
url = (host + @app.send("new_#{typ.to_s.underscore}_path"))
|
204
217
|
full_url(url, params)
|
205
218
|
end
|
206
219
|
|
220
|
+
# Appends params to the url as a query string
|
207
221
|
def self.full_url(u, params)
|
208
222
|
url = u
|
209
223
|
url = "#{u}?#{params.to_query}" unless params.empty?
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turkee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-09 00:00:00.
|
12
|
+
date: 2012-05-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: lockfile
|
16
|
-
requirement: &
|
16
|
+
requirement: &70217997125780 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70217997125780
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rails
|
27
|
-
requirement: &
|
27
|
+
requirement: &70217997123680 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,21 +32,21 @@ dependencies:
|
|
32
32
|
version: 3.1.1
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70217997123680
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rturk
|
38
|
-
requirement: &
|
38
|
+
requirement: &70217997120760 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 2.
|
43
|
+
version: 2.4.0
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70217997120760
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mocha
|
49
|
-
requirement: &
|
49
|
+
requirement: &70217997119040 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70217997119040
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: sqlite3
|
60
|
-
requirement: &
|
60
|
+
requirement: &70217997114560 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70217997114560
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: factory_girl
|
71
|
-
requirement: &
|
71
|
+
requirement: &70217997110980 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 1.3.2
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70217997110980
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec
|
82
|
-
requirement: &
|
82
|
+
requirement: &70217997110120 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: 2.5.0
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70217997110120
|
91
91
|
description: Turkee will help you to create your Rails forms, post the HITs, and retrieve
|
92
92
|
the user entered values from Mechanical Turk.
|
93
93
|
email: jjones@aantix.com
|
@@ -103,6 +103,8 @@ files:
|
|
103
103
|
- lib/generators/turkee/templates/turkee_imported_assignments.rb.erb
|
104
104
|
- lib/generators/turkee/templates/add_completed_tasks.rb.erb
|
105
105
|
- lib/generators/turkee/templates/turkee_migration.rb.erb
|
106
|
+
- lib/generators/turkee/templates/add_imported_assignment_details.rb.erb
|
107
|
+
- lib/generators/turkee/templates/add_hit_duration.rb.erb
|
106
108
|
- lib/generators/turkee/turkee_generator.rb
|
107
109
|
- lib/tasks/turkee.rb
|
108
110
|
- lib/turkee.rb
|