turkee 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- <% turkee_form_for(@survey, params) do |f| %>
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,2]
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::get_all_results
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
- Turkee::TurkeeTask.create_hit(host, hit_title, hit_description, UrlSurvey, num_assignments, reward,
134
- lifetime, qualifications = {}, params = {:url_id => url.id}, opts = {})
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
 
@@ -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, and number of days the HIT should be valid."
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])
@@ -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, :conditions => ['complete = ?', false]
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
- puts "param_hash = #{param_hash}"
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) rescue nil
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
- duration = lifetime.to_i
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 = duration.days.seconds.to_i
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, :form_url => f_url,
91
- :hit_url => h.url, :hit_id => h.id,
92
- :task_type => typ, :complete => false)
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
- puts "#### turk.completed_assignments == turk.hit_num_assignments :: #{turk.completed_assignments} == #{turk.hit_num_assignments}"
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?
@@ -22,6 +22,7 @@ ActiveRecord::Schema.define(:version => 1) do
22
22
  t.decimal "hit_reward", :precision => 10, :scale => 2
23
23
  t.integer "hit_num_assignments"
24
24
  t.integer "hit_lifetime"
25
+ t.integer "hit_duration"
25
26
  t.string "form_url"
26
27
  t.boolean "complete"
27
28
  end
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.0
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.000000000Z
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: &70100423349140 !ruby/object:Gem::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: *70100423349140
24
+ version_requirements: *70217997125780
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rails
27
- requirement: &70100423348080 !ruby/object:Gem::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: *70100423348080
35
+ version_requirements: *70217997123680
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rturk
38
- requirement: &70100423347560 !ruby/object:Gem::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.3.0
43
+ version: 2.4.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70100423347560
46
+ version_requirements: *70217997120760
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: mocha
49
- requirement: &70100423347160 !ruby/object:Gem::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: *70100423347160
57
+ version_requirements: *70217997119040
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: sqlite3
60
- requirement: &70100423346420 !ruby/object:Gem::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: *70100423346420
68
+ version_requirements: *70217997114560
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: factory_girl
71
- requirement: &70100423345240 !ruby/object:Gem::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: *70100423345240
79
+ version_requirements: *70217997110980
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70100423343480 !ruby/object:Gem::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: *70100423343480
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