MultiJson::DecodeError unexpected token at {"email":"foo#bar.com"} - ruby-on-rails

I'm developing a new Ruby on Rails 3.2 application.
This application will receive a periodic json callback with statistics.
The callback i receive is not entirely valid. The json rules are separated by newlines.
The callback POSTs have a content-type header of application/json, and contain exactly one JSON string per line, with each line representing one event. Please note that currently the POST headers define this post as application/json, though it’s not; each line is a valid JSON string, but the overall POST body is not. For example:
This is a example of the callback:
{"email":"foo#bar.com","timestamp":1322000095,"unique_arg":"my unique arg","event":"delivered"}
{"email":"foo#bar.com","timestamp":1322000097,"unique_arg":"my unique arg","event":"click"}
{"email":"foo#bar.com","timestamp":1322000096,"unique_arg":"my unique arg","event":"open"}
When i receive this callback my Rails application crashes with a "MultiJson::DecodeError"
743: unexpected token at '{"email":"foo#bar.com","timestamp":1322000096,"unique_arg":"my unique arg","event":"open"}'
I think the application detects the application/json header and try automatic to parse it.
How can i convert this to a valid JSON object, so i can use this in my controller?
Thanks.

Put
gem 'yajl-ruby' in Gemfile and
require 'yajl/json_gem' config/application.rb

In gem file declare
gem 'yajl-ruby'
It is used to Parse and encode multiple JSON objects to and from streams or strings continuous.
And require 'yajl/json_gem' in application.rb

Put Elements in Brackets:
[{"email":"foo#bar.com","timestamp":1322000095,"unique_arg":"my unique arg","event":"delivered"},
{"email":"foo#bar.com","timestamp":1322000097,"unique_arg":"my unique arg","event":"click"},
{"email":"foo#bar.com","timestamp":1322000096,"unique_arg":"my unique arg","event":"open"}]`

Unable to reproduce your problem by copy-and-pasting the error message token using both ActiveSupport::JSON.decode and MultiJson.decode in a Rails shell. Rails 3.2.1
Any other clues?

This issue is likely due to response body encoded in ISO-8859-1 instead of UTF-8. Possible fix on client side is be convert it back to UTF-8 using ruby 'iconv' encoding methods.

Related

Rails disable JSON parsing of POST/PUT/PATCH body

I want to take a large JSON PUT request and process it entirely in the background with Sidekiq. As such, I do not want to automatically parse the incoming JSON from the request's body.
Whats the best practice for accomplishing this on a controller/action-based level?
As far as I know this is done via Rack middleware, so I don't think you can just disable it for one controller/action right out of the box. You can patch ActionDispatch::ParamsParser similar to what this guy did:
http://www.jkfill.com/2015/02/21/skip-automatic-params-parsing/
You, of course, can write your own middleware that parses the parameters, or specify a custom parser for JSON MIME type.
At last, you can disable the JSON parsing all together. In your config/application.rb add:
config.middleware.swap ActionDispatch::ParamsParser, ActionDispatch::ParamsParser, Mime::JSON => nil

Post request parameters getting truncated in Rails 4.2.2 with content type as "Application/xml"

I have this below observation:
I deployed a sample Rails 4.2.2 application with a controller and action to receive a POST request.
Now If I send a POST request to this application with some POST body say a hash like {"1"=>"hello","2"=>"bye"} and if the content type of the request is "application/xml", I don't receive any parameters in my Rails app.
If I change content type of the same request to some thing else , I will get the parameters properly.
Can some one please tell my why this behaviour is there in Rails 4.2.2 with a POST request having content type as "application/xml".
Automatic parsing of XML bodies was removed in rails 4.0 and extracted into a gem
Even with that gem your request body isn't valid XML.

REST Client and foreign characters

How does one deal with foreign characters in REST Client? Ie.:
RestClient.get "http://api.example.com/1.0/items.json;q=æøå"
which in Ruby on Rails unfortunately returns:
URI::InvalidURIError in MyController#index
bad URI(is not URI?)
The URL works fine in the browser.
According to its docs:
If you need to normalize URIs, e.g. to work with International
Resource Identifiers (IRIs), use the addressable gem
(addressable.rubyforge.org/api/) in your code:
require 'addressable/uri'
RestClient.get(Addressable::URI.parse("http://www.詹姆斯.com/").normalize.to_str)
Or you can try to encode/escape the string beforehand:
http://ruby-doc.org/stdlib-1.9.3/libdoc/uri/rdoc/URI/Escape.html#method-i-encode

Apply monkey patch for JSON parsing in rails

I'm trying to handle edge-case issues with the BigCommerce API returning invalid JSON objects, resulting in un-paired octects as discussed here: A JSON text must at least contain two octets
I believe the solution is to deploy the code (from that thread):
module JSON
def self.parse_nil(json)
JSON.parse(json) if json && json.length >= 2
end
end
parsed = JSON.parse_nil(json)
Where do I deploy this code to apply the patch?
Patches like these are typically added in an otherwise empty .rb file in the /config/initializers directory (see here for an example). Note that the patch should not include the last line:
parsed = JSON.parse_nil(json)
That was added for demonstrative purposes.

(ruby) ruby sockets: how to create a POST request?

How does one create a POST request using TCPSocket in Ruby? Is there a special format to making a post? I have the following but I get a parse error (it's for a rails server):
require 'socket'
s = TCPSocket.open("localhost", 3000)
s.puts("POST /<controller>/<action> HTTP/1.1")
s.puts("Host: localhost:3000")
s.puts("Content-Type: application/x-www-form-urlencoded")
s.puts("Content-Length: 103\r\n\r\n")
The Host: field should not include the port number.
Found this article that may be of some use to you. I especially like Eric Hodel's comment about how to do it with Net::HTTP. I know you specified that you wanted to do TCPSocket.send (presumably because you're working on something slightly more interesting than just sending POSTs), but if you aren't doing something more complicated you may be able to use Net::HTTP and rejoice at how easy it is.

Resources