ruby-aws Amazon Mechanical Turk - ruby

I am trying to create a HIT with a pre-created form using the ruby-aws gem and keep getting a missing params error. I have limited the missing params to the params specific to my form.
It seems my request is not being formatted correctly and there are next to no examples from Amazon. My logs say the the following params are missing:
relationship, price, environmental_consciousness, age, occasion, gender, humor, experience, local, romance, additional_information
Any help is much appreciated!
Below is my current request:
hit = mturk.createHIT(
:Operation => 'CreateHIT',
:Title => 'Find a gift based on user scores',
:Description => 'Find a gift for an individual based on survey scores.',
:MaxAssignments => 3,
:Signature => signature,
:Timestamp => timestamp,
:Reward => { :Amount => 0.25, :CurrencyCode => 'USD' },
:HITLayoutId => '3AV6FF2M2GYMGLRQEKHZ7EBN4EZOJE',
:HitLayoutParameter => {'Name' => 'additional_information', 'Value' => 'TEST'},
:HitLayoutParameter => {'Name' => 'age', 'Value' => '22'},
:HitLayoutParameter => {'Name' => 'environmental_consciousness', 'Value' => '54'},
:HitLayoutParameter => {'Name' => 'experience', 'Value' => '32'},
:HitLayoutParameter => {'Name' => 'gender', 'Value' => 'male'},
:HitLayoutParameter => {'Name' => 'humor', 'Value' => '66'},
:HitLayoutParameter => {'Name' => 'local', 'Value' => '21'},
:HitLayoutParameter => {'Name' => 'occasion', 'Value' => '43'},
:HitLayoutParameter => {'Name' => 'price', 'Value' => '33'},
:HitLayoutParameter => {'Name' => 'relationship', 'Value' => '23'},
:HitLayoutParameter => {'Name' => 'romance', 'Value' => '23'},
:Keywords => 'data collection, gifting, gifts, shopping, gift listings, presents',
:AssignmentDurationInSeconds => 300,
:LifetimeInSeconds => 604800
)

I was able to resolive the issue - AWS has terrible naming conventions. The above example does use the correct format, however HitLayoutParameter must be HITLayoutParameter - Notice the CAPITAL HIT vs Hit.
Also, when submitting multiple parameters, the should only be one HITLayoutParameter that equals an array of Name/Value pairs. Working code below.
Hope this helps someone else!
Best,
~DFO~
hit = mturk.createHIT(
:Operation => 'CreateHIT',
:Title => 'Find a gift based on user scores',
:Description => 'Find a gift for an individual based on survey scores.',
:MaxAssignments => 3,
:Signature => signature,
:Timestamp => timestamp,
:Reward => { :Amount => 0.25, :CurrencyCode => 'USD' },
:HITLayoutId => '3AV6FF2M2GYMGLRQEKHZ7EBN4EZOJE',
:HITLayoutParameter => [
{:Name => 'additional_information', :Value => 'TEST'},
{:Name => 'age', :Value => '22'},
{:Name => 'environmental_consciousness', :Value => '54'},
{:Name => 'experience', :Value => '32'},
{:Name => 'gender', :Value => 'male'},
{:Name => 'humor', :Value => '66'},
{:Name => 'local', :Value => '21'},
{:Name => 'occasion', :Value => '43'},
{:Name => 'price', :Value => '33'},
{:Name => 'relationship', :Value => '23'},
{:Name => 'romance', :Value => '23'}
],
:Keywords => 'data collection, gifting, gifts, shopping, gift listings, presents',
:AssignmentDurationInSeconds => 300,
:LifetimeInSeconds => 604800
)

Related

Ruby hash of hashes, how to get key if there is a key value match into the nested hashes

I have a ruby hash with this structure:
jotform = {
'1' => {
'name' => 'theGreat',
'order' => '1',
'text' => 'xxxxx',
'type' => 'control_head'
},
'3' => {
'name' => 'clickTo',
'order' => '2',
'text' => '<p>Final date to apply is August 29</p>',
'type' => 'control_text'
},
'4' => {
'name' => 'personalDetails',
'order' => '3',
'text' => 'Personal Details',
'type' => 'control_head'
},
'5' => {
'name' => 'name',
'order' => '4',
'sublabels' =>
'{"prefix":"Prefix","first":"First Name","middle":"Middle Name","last":"Last Name","suffix":"Suffix"}',
'text' => 'Name',
'type' => 'control_fullname',
'answer' => {
'first' => 'Example',
'last' => 'Example'
},
'prettyFormat' => 'Example'
},
'9' => {
'name' => 'country',
'order' => '5',
'text' => 'Country',
'type' => 'control_dropdown',
'answer' => 'Germany'
},
'10' => {
'name' => 'email',
'order' => '6',
'text' => 'Email',
'type' => 'control_email',
'answer' => 'picco#example.com'
},
'15' => {
'name' => 'pageBreak',
'order' => '8',
'text' => 'Page Break',
'type' => 'control_pagebreak'
},
'16' => {
'name' => 'contributions',
'order' => '9',
'text' => 'Contributions',
'type' => 'control_head'
}
}
This is a payload that I receive from jotform and I have to process in my app.
The issue is that I don't know the field order: this hash has some keys ('1', '2', …) that are equivalent to the form answer.
I must get the name in Pretty Format and the email, so I'm trying to get these values.
Here the email has key '10' and the name has key '5' but they can change in the next form.
I try with
jotform.select { |_key, hash| hash['name'] == 'email' }
But it returns
{
'10' => {
'name' => 'email',
'order' => '6',
'text' => 'Email',
'type' => 'control_email',
'answer' => 'example#example.com'
}
}
I need to get the key ('10') if there is a match into this key's value but I cannot understand how.
From the result of your select call:
h = jotform.select{ |key, hash| hash["name"] == "email" }
You can get the key via:
h.keys.first
#=> "10"
And the value via:
h.values.first["answer"]
#=> "example#example.com"
first is needed because there could (in theory) be multiple entries for email.
Well, that's a weird format.
I'm not sure I understand it, but assuming that name is unique, you could reindex your hash and use name as key:
new_data = jotform.map do |id, h|
key = h.delete 'name'
[key, h.merge('id' => id)]
end.to_h
The new format looks like :
{"theGreat"=>
{"order"=>"1", "text"=>"xxxxx", "type"=>"control_head", "id"=>"1"},
"clickTo"=>
{"order"=>"2",
"text"=>"<p>Final date to apply is August 29</p>",
"type"=>"control_text",
"id"=>"3"},
"personalDetails"=>
{"order"=>"3",
"text"=>"Personal Details",
"type"=>"control_head",
"id"=>"4"},
"name"=>
{"order"=>"4",
"sublabels"=>
"{\"prefix\":\"Prefix\",\"first\":\"First Name\",\"middle\":\"Middle Name\",\"last\":\"Last Name\",\"suffix\":\"Suffix\"}",
"text"=>"Name",
"type"=>"control_fullname",
"answer"=>{"first"=>"Example", "last"=>"Example"},
"prettyFormat"=>"Example",
"id"=>"5"},
"country"=>
{"order"=>"5",
"text"=>"Country",
"type"=>"control_dropdown",
"answer"=>"Germany",
"id"=>"9"},
"email"=>
{"order"=>"6",
"text"=>"Email",
"type"=>"control_email",
"answer"=>"picco#example.com",
"id"=>"10"},
"pageBreak"=>
{"order"=>"8",
"text"=>"Page Break",
"type"=>"control_pagebreak",
"id"=>"15"},
"contributions"=>
{"order"=>"9", "text"=>"Contributions", "type"=>"control_head", "id"=>"16"}}
No information has been lost, and it should be easier to access. In order to get the email address, you can simply use:
new_data["email"]["answer"]
#=> "picco#example.com"

Fedex Ruby Gem: Customs Value is required - how to add?

I'm working with the Ruby gem 'FedEx', https://github.com/jazminschroeder/fedex.
I've set up my code for a development mode and I'm testing making a shipment.
However, I get stuck with the following error:
C:/Ruby22/lib/ruby/gems/2.2.0/gems/fedex-.10.1/lib/fedex/request/shipment.rb:134:in 'failure_response': Customs Value is required. (Fedex:: RateError) from C: /Ruby22/lib/ruby/gems/2.2.0/gems/fedex-.10.1/lib/fedex/request/shipment.rb:32:in 'process_request' from C: /Ruby22/lib/ruby/gems/2.2.0/gems/fedex-3.10.1/lib/fedex/shipment.rb:57:in 'ship' from C: /Ruby22/bin/css_fedex_v1.rb:92:in ''
It seems that I need to parse a 'Customs Value', probably as part of my 'packages' hash. However, I'm unable to find the relevant field for me to enter this in. Anyone who's experienced this and found a solution?
My code is as below:
require 'fedex'
fedex = Fedex::Shipment.new(:key => '***',
:password => '***',
:account_number => '***',
:meter => '***',
:mode => 'development')
shipper = { :name => "***",
:company => "***",
:phone_number => "***",
:address => "***",
:city => "***",
:postal_code => "***",
:country_code => "DK" }
recipient = { :name => "***",
:company => "***",
:phone_number => "***",
:address => "***",
:city => "***",
:postal_code => "***",
:country_code => "GB",
:residential => "false" }
packages = []
packages << {:weight => {:units => "LB", :value => 1}}
shipping_options = {:packaging_type => "YOUR_PACKAGING",
:drop_off_type => "REGULAR_PICKUP"}
rate = fedex.rate(:shipper=>shipper,
:recipient => recipient,
:packages => packages,
:shipping_options => shipping_options)
ship = fedex.ship(:shipper=>shipper,
:recipient => recipient,
:packages => packages,
:service_type => "INTERNATIONAL_PRIORITY",
:shipping_options => shipping_options)
puts ship[:completed_shipment_detail][:operational_detail][:transit_time]
Customs value is declared in their docs:
https://github.com/jazminschroeder/fedex/commit/9f1d4c67b829aaa4eeba9090c1a45d3bd507aab3#diff-4f122efb7c0d98120d8b7f0cd00998e4R106
customs_value = { :currency => "USD",
:amount => "200" }
As I understand you can pass it into the commodities hash or keep it separate.

Elastic Search Multiple Fields

I'm using Tire to index and search a database of cars:
create :mappings => {
:cars => {
:properties => {
:id => {:type => 'string', :index => 'not_analyzed', :include_in_all => true},
:user_id => {:type => 'string', :index => 'not_analyzed'},
:name => {:type => 'string', :analyzer => 'snowball' },
:time => {:type => 'long', :index => 'not_analyzed'},
:origin_country => {:type => 'string', :analyzer => 'keyword', :include_in_all => false},
:origin_state => {:type => 'string', :analyzer => 'keyword', :include_in_all => false},
:origin_city => {:type => 'string', :analyzer => 'keyword', :include_in_all => false},
:dealer_name => {:type => 'string', :analyzer => 'snowball', :boost => 1.5, :include_in_all => false}
}
}
}
And queries look like:
s = Tire.search Search.index_name do
query do |query|
query.text :_all, downcased_query, :type => :phrase
end
end
Right now if you search for "New York Joe Dealer" it will match if there is a dealer_name is "Joe Dealer" or if the origin_state is "New York" but not both. Is there a way to match origin_state is "New York" and "dealer_name" is "Joe Dealer" (or either)? The idea is I want a user to enter in a fre-form query string and be able to find the best matches possible and to a user they would expect to enter New York Joe Dealer and find all cars sold at Joe Dealer in New York (or all cars in New York or at Joe Dealer ranked lower).
The correct solution would be to use the multi_match query to perform the same query against multiple fields. It's supported in Tire, see https://github.com/karmi/tire/blob/master/test/integration/match_query_test.rb.
Tire.search Search.index_name do
query do |query|
query.match :dealer_name, downcased_query
query.match :origin_state, downcased_query
end
end
You can even use the phrase type if the query would contain both the dealer and state info in correct order, such as "New York Joe Dealer".
The solution was to move to a "match" type filter, and diable :type => :phrase, so:
query do |query|
query.match :_all, downcased_query
end
There are still some issues with sorting so that time is still a big input, but this resolves many of the issues.

What's the best way to replace a string inside a string in ruby?

I have a bunch of these:
'link' => "http://twitter.com/home?status=Check out "{title}" {url}",
And Want to replace the {title} and {url} bits.
I'm currently doing this with gsub:
l.gsub! "{url}", URI::encode(#opts[:url])
l.gsub! "{title}", URI::encode(#opts[:title])
But I have the feeling there's a much better way to do this than with gsub...
#
This is an edit / addition to clarify:
class SocialBookmarkMaker
require 'open-uri'
attr_accessor :opts
def initialize(opts)
#opts = ##default_opts.merge opts
end
##default_opts = {
:icon_folder => "/images/icons/social_aquatic/24 X 24",
:sites => ['facebook', 'twitter', 'delicious', 'digg', 'stumbleupon', 'reddit', 'technorati', ],
:ext => 'png',
:url => 'not provided',
:title => 'not provided',
}
##bookmarks = {
'yahoo' => {
'name' => 'Yahoo! My Web',
'link' => 'http://myweb2.search.yahoo.com/myresults/bookmarklet?u={url}&t={title}',
},
'google' => {
'name' => 'Google Bookmarks',
'link' => 'http://www.google.com/bookmarks/mark?op=edit&bkmk={url}&title={title}',
},
'windows' => {
'name' => 'Windows Live',
'link' => 'https://favorites.live.com/quickadd.aspx?url={url}&title={title}',
},
'facebook' => {
'name' => 'Facebook',
'link' => 'http://www.facebook.com/sharer.php?u={url}&t={title}',
},
'digg' => {
'name' => 'Digg',
'link' => 'http://digg.com/submit?phase=2&url={url}&title={title}',
},
'ask' => {
'name' => 'Ask',
'link' => 'http://myjeeves.ask.com/mysearch/BookmarkIt?v=1.2&t=webpages&url={url}&title={title}',
},
'technorati' => {
'name' => 'Technorati',
'link' => 'http://www.technorati.com/faves?add={url}',
},
'delicious' => {
'name' => 'del.icio.us',
'link' => 'http://del.icio.us/post?url={url}&title={title}',
},
'stumbleupon' => {
'name' => 'StumbleUpon',
'link' => 'http://www.stumbleupon.com/submit?url={url}&title={title}',
},
'squidoo' => {
'name' => 'Squidoo',
'link' => 'http://www.squidoo.com/lensmaster/bookmark?{url}'
},
'netscape' => {
'name' => 'Netscape',
'link' => 'http://www.netscape.com/submit/?U={url}&T={title}',
},
'slashdot' => {
'name' => 'Slashdot',
'link' => 'http://slashdot.org/bookmark.pl?url={url}&title={title}',
},
'reddit' => {
'name' => 'reddit',
'link' => 'http://reddit.com/submit?url={url}&title={title}',
},
'furl' => {
'name' => 'Furl',
'link' => 'http://furl.net/storeIt.jsp?u={url}&t={title}',
},
'blinklist' => {
'name' => 'BlinkList',
'link' => 'http://blinklist.com/index.php?Action=Blink/addblink.php&Url={url}&Title={title}',
},
'dzone' => {
'name' => 'dzone',
'link' => 'http://www.dzone.com/links/add.html?url={url}&title={title}',
},
'swik' => {
'name' => 'SWiK',
'link' => 'http://stories.swik.net/?submitUrl&url={url}'
},
'shoutwire' => {
'name' => 'Shoutwrie',
'link' => 'http://www.shoutwire.com/?p=submit&&link={url}',
},
'blinkbits' => {
'name' => 'Blinkbits',
'link' => 'http://www.blinkbits.com/bookmarklets/save.php?v=1&source_url={url}',
},
'spurl' => {
'name' => 'Spurl',
'link' => 'http://www.spurl.net/spurl.php?url={url}&title={title}',
},
'diigo' => {
'name' => 'Diigo',
'link' => 'http://www.diigo.com/post?url={url}&title={title}',
},
'tailrank' => {
'name' => 'Tailrank',
'link' => 'http://tailrank.com/share/?link_href={url}&title={title}',
},
'rawsugar' => {
'name' => 'Rawsugar',
'link' => 'http://www.rawsugar.com/tagger/?turl={url}&tttl={title}&editorInitialized=1',
},
'twitter' => {
'name' => 'Twitter',
'link' => "http://twitter.com/home?status=Check out "{title}" {url}",
},
}
def self.bookmarks
##bookmarks
end
def icon_loc(site)
"http://common-resources.---.net.s3.amazonaws.com#{#opts[:icon_folder]}/#{site}.#{#opts[:ext]}"
end
def link_url(site)
l = SocialBookmarkMaker.bookmarks[site]['link']
l.gsub! "{url}", URI::encode(#opts[:url])
l.gsub! "{title}", URI::encode(#opts[:title])
l
end
end
shared/social_bookmarks/standard.html.haml
- opts ||= {}
- opts.merge! :url => request.url
- opts.merge! :title => "---.net: #{#layout[:social_bookmark_title] || #layout[:title] || default_view_title}"
- b = SocialBookmarkMaker.new opts
- b.opts[:sites].each do |site|
= link_to(image_tag( b.icon_loc(site) ), b.link_url(site), :title => "Share on #{SocialBookmarkMaker.bookmarks[site]['name']}")
I then call this like this in my rails layout:
render :partial => "shared/social_bookmarks/standard", :locals => { :opts => {:icon_folder => "/images/icons/social_aquatic/48 X 48" }}
Either you change your string to look like
"http://twitter.com/home?status=Check out "%{title}" %{url}"
and then use printf with a Hash
s = "http://twitter.com/home?status=Check out "%{title}" %{url}"
# you can of course use #opts as the Hash here.
s = s % {:title => "abc", :url => "def"} # => "http://twitter.com/home?status=Check out "abc" def"
and accept that it only works with Ruby 1.9.2 and upwards, or you continue using gsub but using the block syntax to condense it:
s.gsub!(/\{(.+?)\}/) do |m|
#opts[$1.to_sym]
end
You can just embed the variables directly in the string
'link' => "http://twitter.com/home?status=Check out "#{title}" #{url}"

Recurrence with Google calendar ruby API V3

Using the following code, I've not been able to push any recurring events to google calendar. However, take off the 'recurrence' item from event and it works.
What am I doing wrong ?
event = {
'summary' => 'Appointment',
'location' => 'Somewhere',
'start' => {
'dateTime' => '2011-06-03T10:00:00.000-07:00'
},
'end' => {
'dateTime' => '2011-06-03T10:25:00.000-07:00'
},
'recurrence' => [
"RRULE:FREQ=DAILY;COUNT=5"
]
}
result = #client.execute(:api_method => #service.events.insert,
:parameters => {'calendarId' => 'hg9a7o16bm6dj0tmuo481499mc#group.calendar.google.com'},
:body_object => event,
:headers => {'Content-Type' => 'application/json'})
puts result.data.id.to_s
The timezone needs to be set in a seperate field as this
event = {
'summary' => 'Appointment',
'location' => 'Somewhere',
'start' => {
'dateTime' => '2011-06-03T10:00:00.000-07:00',
'timeZone' => 'America/Montreal'
},
'end' => {
'dateTime' => '2011-06-03T10:25:00.000-07:00',
'timeZone' => 'America/Montreal'
},
'recurrence' => [
"RRULE:FREQ=DAILY;COUNT=5"
]
}
Please try with "RRULE:FREQ=WEEKLY;UNTIL=20120701T160000Z";

Resources