I'm new to Rails (but not new to web development in general). I'm using the mws-connect gem (https://github.com/devmode/mws) to connect to Amazon Marketplace Web Service. I'm trying to cancel an order, and according to the Amazon MWS API docs, the following xml code is what needs to be sent (as far as I can tell) :
<?xml version="1.0"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier> M_IDENTIFIER</MerchantIdentifier>
</Header>
<MessageType>
OrderAcknowledgment
</MessageType>
<Message>
<MessageID>1</MessageID>
<OrderAcknowledgement>
<AmazonOrderID>050-1234567-1234567</AmazonOrderID>
<StatusCode>Failure</StatusCode>
<CancelReason>Reason for cancellation</CancelReason>
</OrderAcknowledgment>
</Message>
</AmazonEnvelope>
The gem documentation isn't clear on how to do this since the examples are all for how to add or update a product listing, which I tested and works just fine. I've tried about every way I can think of to just build the "feed" request manually to submit it and use the rest of the class to handle the submission stuff since I know that works. The current example of the code that I have in a SalesOrder class is:
def self.cancel_amazon_order(amazon_order_id, cancel_reason)
mws = Mws.connect(
merchant: 'merchant_id',
access: 'access_key',
secret: 'secret'
)
cancel_feed = Mws::Feed.new 'merchant_id', :order_acknowledgement do
#messages << {
MessageID: '1',
OrderAcknowledgement: {
AmazonOrderID: amazon_order_id,
StatusCode: 'Failure',
CancelReason: cancel_reason
}
}
end
end
This code doesn't throw any errors, but when I try to do cancel_feed.to_xml (what I can see is the next step towards submitting the feed), I get an error saying
ArgumentError: Namespace indent has not been defined
Are there any rails pros out there that might have an idea how to make this gem work, either the to_xml method, or better yet how to get the cancel itself through? I feel like I'm not too far off. I'm coming from a PHP background, so my thought process on this is probably off a bit. I've loved Rails so far, but I'm pulling my hair out on this one, any help is appreciated!
In case anyone is interested, the solution I ended up with was:
mws = Mws.connect merchant: AMAZON_CONFIG['merchant_id'], access: AMAZON_CONFIG['access'], secret: AMAZON_CONFIG['secret']
cancel_xml = Nokogiri::XML::Builder.new do | xml |
xml.AmazonEnvelope('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:noNamespaceSchemaLocation' => 'amznenvelope.xsd') {
xml.Header {
xml.DocumentVersion '1.01'
xml.MerchantIdentifier AMAZON_CONFIG['merchant_id']
}
xml.MessageType 'OrderAcknowledgement'
xml.Message {
xml.MessageID '1'
xml.OrderAcknowledgement {
xml.AmazonOrderID order_id
xml.StatusCode 'Failure'
items.each do | item |
xml.Item {
xml.AmazonOrderItemCode item[:item_code]
xml.CancelReason 'NoInventory'
}
end
}
}
}
end.to_xml
mws.feeds.submit cancel_xml, {feed_type: :order_acknowledgement}
Related
I'm using the DocuSign ruby client (https://github.com/docusign/docusign-ruby-client) on ruby on rails to send a document via email to some clients, but when I deploy the project after 15 minutes the request between the application and DocuSign gets "paused". For some reason the gem creates the request but doesn't send it as you can see in the next image where I enable the debug in the gem:
In that point the log doesn't print any more after 15 minutes.
The code that send the message in my app is:
access_token = "xxxxxxx"
account_id = "xxxxxxxxx"
base_path = "xxxxxxxxxx"
envelope_args = {
signer_email: contact.email,
signer_name: contact.name,
template_id: document.docusign_id
}
#args = {
account_id: account_id,
base_path: base_path,
access_token: access_token,
envelope_args: envelope_args
}
envelope_args = #args[:envelope_args]
# 1. Create the envelope request object
envelope_definition = make_envelope(envelope_args)
# 2. Call Envelopes::create API method
# Exceptions will be caught by the calling function
envelope_api = create_envelope_api(#args)
envelope_api.create_envelope #args[:account_id], envelope_definition
I don't know what can I do.
Thank you
Your screenshot shows everything happening at 18:29:05 -- I don't understand the issue.
Also, have you tried install/using the RoR code example?
See if it has the same problem.
We looked for the issue in our code, but we saw that in the step which the request is send in the gem here always freezes. So we debugged there and we saw that curl was being used for ruby. At that point we saw that curl was trying to reconnect with Docusign but it wasn't success, so we found this issue in the version of curl that we had (https://github.com/curl/curl/issues/4499 )
To fix it we updated the version to the latest, and it fixed the issue.
Thanks for your answers.
I understand the whole process of dialogflow and I have a working deployed bot with 2 different intents. How do I actually get the response from the bot when a user answers questions? (I set the bot on fulfillment to go to my domain). Using rails 5 app and it's deployed with Heroku.
Thanks!
If you have already set the GOOGLE_APPLICATION_CREDENTIALS path to the jso file, now you can test using a ruby script.
Create a ruby file -> ex: chatbot.rb
Write the code bellow in the file.
project_id = "Your Google Cloud project ID"
session_id = "mysession"
texts = ["hello"]
language_code = "en-US"
require "google/cloud/dialogflow"
session_client = Google::Cloud::Dialogflow::Sessions.new
session = session_client.class.session_path project_id, session_id
puts "Session path: #{session}"
texts.each do |text|
query_input = { text: { text: text, language_code: language_code } }
response = session_client.detect_intent session, query_input
query_result = response.query_result
puts "Query text: #{query_result.query_text}"
puts "Intent detected: #{query_result.intent.display_name}"
puts "Intent confidence: #{query_result.intent_detection_confidence}"
puts "Fulfillment text: #{query_result.fulfillment_text}\n"
end
Insert your project_id. You can find this information on your agent on Dialogflow. Click on the gear on the right side of the Agent's name in the left menu.
Run the ruby file in the terminal or in whatever you using to run ruby files. Then you see the bot replying to the "hello" message you have sent.
Obs: Do not forget to install the google-cloud gem:
Not Entirely familiar with Dilogflow, but if you want to receive a response when an action occurs on another app this usually mean you need to receive web-hooks from them
A WebHook is an HTTP callback: an HTTP POST that occurs when something happens; a simple event-notification via HTTP POST. A web application implementing WebHooks will POST a message to a URL when certain things happen.
I would recommend checking their fulfillment documentation for an example. Hope this helps you out.
I have an API built using Spray that handles file uploads.
I am trying to write a test for the upload functionality but I'm not getting anywhere fast. I'm nots sure how to structure the test to simulate a file upload.
I have the following test...
"Valid POST Requests should return success" in {
Post("/upload", HttpEntity(MediaTypes.`multipart/form-data`, """{"filename":"a.wav"}""")) ~>
sealRoute(uploadRoute) ~> check {
response.status should be equalTo OK
responseAs[String] === "..."
}
}
Running this produces the following error message...
Content-Type with a multipart media type must have a non-empty 'boundary' parameter' is not equal to ...
This seems like an error message similar to how to mock POST/Upload requests using apache bench where you have to specify a post file and the boundary to separate the form items.
I was hoping for something closer to how CURL works.
Either way, can anyone point me in the right direction as to how I correctly structure such a test?
Thanks
So I managed to get this working by cobbling together some code from a variety of posts I found - primarily posts relating to using spray-client to do file uploads.
Probably not the prettiest but works for me! :)
"Valid POST Requests should return success" in {
val file = new File("a.wav")
val httpEntity = HttpEntity(MediaTypes.`multipart/form-data`, HttpData(file)).asInstanceOf[HttpEntity.NonEmpty]
val formFile = FormFile("file", httpEntity)
val mfd = MultipartFormData(Seq(BodyPart(formFile, "file")))
Post("/upload", mfd) ~> sealRoute(uploadRoute) ~> check {
response.status should be equalTo OK
body.contentType.toString() === "application/json; charset=UTF-8"
responseAs[String] === "Success!"
}
}
I have the same issue, or question.
Try adding a boundary by doing:
Post("/upload", HttpEntity(MediaTypes.multipart/form-data.withBoundary("-somerandomboundary"), """{"filename":"a.wav"}""")) ~>
Although, you might face the next bump I face, which is an error saying it requires a start boundary.
I'm trying to use Amazon's API and search for a book using the following code and the amazon ecs gem which is part of my Ruby on Rails application:
Amazon::Ecs.options = {
:AWS_access_key_id => 'myaccesskeyid',
:AWS_secret_key => 'mysecretkey'
}
res = Amazon::Ecs.item_search('ruby')
puts res
In the terminal I think I am getting a response because I end up getting back:
<Amazon::Ecs::Response:0x000001069911d0>
How do I access the data or parse through this?
According to the docs you can check that your response object doesn't have any errors and check the total results using:
res.has_error? # return true if there is an error
res.total_results # return total results
Assuming that you're response object is OK, you can traverse through each item and pull out the data you are interested in. Eg:
res.items.each do |item|
# retrieve string value using XML path
item.get('ASIN')
item.get('ItemAttributes/Title')
end
Not sure if you have tried this already but looks like a good place to start.
403 Forbidden likely means that you're not correctly sending through your AWS access key and secret key.
Amazon::Ecs.options = {
:AWS_access_key_id => 'myaccesskeyid',
:AWS_secret_key => 'mysecretkey'
}
'myaccesskeyid' and 'mysecretkey" should be alphanumerics that you receive from AWS
Im trying to create a table on BigQuery - I have a single dataset and need to use the api to add a table and import data (json.tar.gz) from cloud storage. I need to be able to use the ruby client to automate the whole process. I have two questions:
I have read the docs and tried to get it to upload (code below) and have not been successful and have absolutely no idea what Im doing wrong. Could somebody please enlighten me or point me in the right direction?
Once I make the request, how do I know when the job has actually finished? From the API, I presume Im meant to use a jobs.get request? Having not completed the first part I have been unable to get to look at this aspect.
This is my code below.
config= {
'configuration'=> {
'load'=> {
'sourceUris'=> ["gs://person-bucket/person_json.tar.gz"],
'schema'=> {
'fields'=> [
{ 'name'=>'person_id', 'type'=>'integer' },
{ 'name'=> 'person_name', 'type'=>'string' },
{ 'name'=> 'logged_in_at', 'type'=>'timestamp' },
]
},
'destinationTable'=> {
'projectId'=> "XXXXXXXXX",
'datasetId'=> "personDataset",
'tableId'=> "person"
},
'createDisposition' => 'CREATE_IF_NEEDED',
'maxBadRecords'=> 10,
}
},
'jobReference'=>{'projectId'=>XXXXXXXXX}
}
multipart_boundary="xxx"
body = "--#{multipart_boundary}\n"
body += "Content-Type: application/json; charset=UTF-8\n\n"
body += "#{config.to_json}\n"
body += "--#{multipart_boundary}\n"
body +="Content-Type: application/octet-stream\n\n"
body += "--#{multipart_boundary}--\n"
param_hash = {:api_method=> bigquery.jobs.insert }
param_hash[:parameters] = {'projectId' => 'XXXXXXXX'}
param_hash[:body] = body
param_hash[:headers] = {'Content-Type' => "multipart/related; boundary=#{multipart_boundary}"}
result = #client.execute(param_hash)
puts JSON.parse(result.response.header)
I get the following error:
{"error"=>{"errors"=>[{"domain"=>"global", "reason"=>"wrongUrlForUpload", "message"=>"Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/bigquery/v2/projects/XXXXXXXX/jobs"}], "code"=>400, "message"=>"Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/bigquery/v2/projects/XXXXXXXX/jobs"}}
From the request header, it appears to be going to the same URI the error says it should go to, and I am quite at a loss for how to proceed. Any help would be much appreciated.
Thank you and have a great day!
Since this is a "media upload" request, there is a slightly different protocol for making the request. The ruby doc here http://rubydoc.info/github/google/google-api-ruby-client/file/README.md#Media_Upload describes it in more detail. I'd use resumable upload rather than multipart because it is simpler.
Yes, as you suspected, the way to know when it is done is to do a jobs.get() to look up the status of the running job. The job id will be returned in the response from jobs.insert(). If you want more control, you can pass your own job id, so that in the event that the jobs.insert() call returns an error you can find out whether the job actually started.
Thank you for that. Answer resolved. Please see here :
How to import a json from a file on cloud storage to Bigquery
I think that the line of code in the docs for the resumable uploads section (http://rubydoc.info/github/google/google-api-ruby-client/file/README.md#Media_Upload) should read:
result = client.execute(:api_method => drive.files.insert,
Otherwise, this line will throw an error with 'result' undefined:
upload = result.resumable_upload