Class: Turkee::TurkeeTask

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/models/turkee_task.rb

Constant Summary collapse

HIT_FRAMEHEIGHT =
1000

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.clear_all_turks(force = false) ⇒ Object

DON’T PUSH THIS BUTTON UNLESS YOU MEAN IT. :)



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/models/turkee_task.rb', line 99

def self.clear_all_turks(force = false)
  # Do NOT execute this function if we're in production mode
  raise "You can only clear turks in the sandbox/development environment unless you pass 'true' for the force flag." if Rails.env == 'production' && !force

  hits = RTurk::Hit.all

  logger.info "#{hits.size} reviewable hits. \n"

  unless hits.empty?
    logger.info "Approving all assignments and disposing of each hit."

    hits.each do |hit|
      begin
        hit.expire!
        hit.assignments.each do |assignment|
          logger.info "Assignment status : #{assignment.status}"
          assignment.approve!('__clear_all_turks__approved__') if assignment.status == 'Submitted'
        end

        turkee_task = TurkeeTask.find_by_hit_id(hit.id)
        turkee_task.complete_task

        hit.dispose!
      rescue Exception => e
        # Probably a service unavailable
        logger.error "Exception : #{e.to_s}"
      end
    end
  end

end

.create_hit(host, hit_title, hit_description, typ, num_assignments, reward, lifetime, duration = nil, qualifications = {}, params = {}, opts = {}) ⇒ Object

Creates a new Mechanical Turk task on AMZN with the given title, desc, etc



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/models/turkee_task.rb', line 68

def self.create_hit(host, hit_title, hit_description, typ, num_assignments, reward, lifetime,
                    duration = nil, qualifications = {}, params = {}, opts = {})
  model = typ.to_s.constantize
  f_url = build_url(host, model, params, opts)

  h = RTurk::Hit.create(:title => hit_title) do |hit|
    hit.assignments = num_assignments
    hit.description = hit_description
    hit.reward = reward
    hit.lifetime = lifetime.to_i.days.seconds.to_i
    hit.duration = duration.to_i.hours.seconds.to_i if duration
    hit.question(f_url, :frame_height => HIT_FRAMEHEIGHT)
    unless qualifications.empty?
      qualifications.each do |key, value|
        hit.qualifications.add key, value
      end
    end
  end

  TurkeeTask.create(:sandbox => RTurk.sandbox?,
                    :hit_title => hit_title, :hit_description => hit_description,
                    :hit_reward => reward.to_f, :hit_num_assignments => num_assignments.to_i,
                    :hit_lifetime => lifetime, :hit_duration => duration,
                    :form_url => f_url, :hit_url => h.url,
                    :hit_id => h.id, :task_type => typ,
                    :complete => false)

end

.process_hits(turkee_task = nil) ⇒ Object

Use this method to go out and retrieve the data for all of the posted Turk Tasks.

Each specific TurkeeTask object (determined by task_type field) is in charge of
accepting/rejecting the assignment and importing the data into their respective tables.


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/models/turkee_task.rb', line 22

def self.process_hits(turkee_task = nil)

  begin
    # Using a lockfile to prevent multiple calls to Amazon.
    Lockfile.new('/tmp/turk_processor.lock', :max_age => 3600, :retries => 10) do

      turks = task_items(turkee_task)

      turks.each do |turk|
        hit = RTurk::Hit.new(turk.hit_id)

        callback_models = Set.new
        hit.assignments.each do |assignment|
          next unless (assignment.status)
          next if assignment_exists?(assignment)

          model, param_hash = map_imported_values(assignment, turk.task_type)
          next if model.nil?

          callback_models << model

          result = save_imported_values(model, param_hash)

          # If there's a custom approve? method, see if we should approve the submitted assignment
          #  otherwise just approve it by default
          turk.process_result(assignment, result)

          TurkeeImportedAssignment.record_imported_assignment(assignment, result, turk)
        end

        turk.set_expired?(callback_models) if !turk.set_complete?(hit, callback_models)
      end
    end
  rescue Lockfile::MaxTriesLockError => e
    logger.info "TurkTask.process_hits is already running or the lockfile /tmp/turk_processor.lock exists from an improperly shutdown previous process. Exiting method call."
  end

end

.save_imported_values(model, param_hash) ⇒ Object



61
62
63
64
65
# File 'lib/models/turkee_task.rb', line 61

def self.save_imported_values(model, param_hash)
  key = model.to_s.underscore.gsub('/','_') # Namespaced model will come across as turkee/turkee_study,
                                            #  we must translate to turkee_turkee_study"
  model.create(param_hash[key])
end

Instance Method Details

#complete_taskObject



131
132
133
134
# File 'lib/models/turkee_task.rb', line 131

def complete_task
  self.complete = true
  save!
end

#increment_complete_assignmentsObject



173
174
175
176
177
178
# File 'lib/models/turkee_task.rb', line 173

def increment_complete_assignments
  raise "Missing :completed_assignments attribute. Please upgrade Turkee to the most recent version." unless respond_to?(:completed_assignments)

  self.completed_assignments += 1
  save
end

#initiate_callback(method, models) ⇒ Object



155
156
157
# File 'lib/models/turkee_task.rb', line 155

def initiate_callback(method, models)
  models.each { |model| model.send(method, self) if model.respond_to?(method) }
end

#process_result(assignment, result) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/models/turkee_task.rb', line 159

def process_result(assignment, result)
  if result.errors.size > 0
    logger.info "Errors : #{result.inspect}"
    assignment.reject!('Failed to enter proper data.')
  elsif result.respond_to?(:approve?)
    logger.debug "Approving : #{result.inspect}"
    self.increment_complete_assignments
    result.approve? ? assignment.approve!('') : assignment.reject!('Rejected criteria.')
  else
    self.increment_complete_assignments
    assignment.approve!('')
  end
end

#set_complete?(hit, models) ⇒ Boolean

Returns:

  • (Boolean)


136
137
138
139
140
141
142
143
144
145
# File 'lib/models/turkee_task.rb', line 136

def set_complete?(hit, models)
  if completed_assignments?
    hit.dispose!
    complete_task
    initiate_callback(:hit_complete, models)
    return true
  end

  false
end

#set_expired?(models) ⇒ Boolean

Returns:

  • (Boolean)


147
148
149
150
151
152
153
# File 'lib/models/turkee_task.rb', line 147

def set_expired?(models)
  if expired?
    self.expired = true
    save!
    initiate_callback(:hit_expired, models)
  end
end