Setting a blank custom header in ruby on rails - ruby-on-rails

I'm writing a REST server using Ruby on rails.
Some of the communication with the client is by setting certain custom headers to predefined values. In certain situations the server is expected to respond with a custom header that is an empty string. My problem is that rails seems to omit any blank headers from the response (it will even omit a whitespace header).
This is my current code:
config.action_dispatch.default_headers = {
'X-WOPI-EmptyLock' => "",
'X-WOPI-FullLock' => "astring",
'Random-header' => "with value",
'Random-empty-header' => ""
}
But the response will only contain headers which are not empty strings:
Resulting headers in response
Curl response headers
Is there some way to configure rails to still send headers even if they are empty?

You can set your custom headers in config/application.rb file
Ex:
config.action_dispatch.default_headers = {
'Custom-Header1' => "", # without value
'Custom-Header2' => "with value"
}
Note: restart rails server after made changes
In response
Custome-Header1 →
Custome-Header2 →with value
Updated answer
Here is my controller code as below
def home
response.headers["My-Custome-Header"] = "With value"
response.headers["My-Custome-Header-2"] = "" # Without value
render json: {data: "It's working my friend"}
end
And required output as shown in screenshot
Hope this will help you.

Related

How do I iterate over this JSON object?

This is an object that is returned as a response in an HTTP POST request:
res.body
=> "{\"id\":\"a3adasfaf3\",\"url\":\"https://someurl/a3adasfaf3\",\"created\":\"2016-05-30T07:00:58Z\",\"modified\":\"2016-05-30T07:00:58Z\",\"files_hash\":\"cljhlk2j3l2kj34hlke18\",\"language\":\"ruby\",\"title\":\"Some weird hello world message\",\"public\":false,\"owner\":\"kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k\",\"files\":[{\"name\":\"Some-weird-hello-world-message.rb\",\"content\":\"puts \\\"Some weird hello world message.\\\"\\r\\n\"}]}"
I am trying to pull out, and translate the various attributes of that response. For instance, at the very least the id and url.
How do I do this?
For the record, I am using Ruby's NET/HTTP std lib to send the POST request and get back this response.
Edit 1
For bonus points, all I want is the actual value stored in each attribute (i.e. the actual id (which is just a string) and a url (which is a typical URL). So if you included how I might both access that attribute and then sanitize it at the same time that would be awesome.
Use JSON.parse to parse the response.
response = "{\"id\":\"a3adasfaf3\",\"url\":\"https://someurl/a3adasfaf3\",\"created\":\"2016-05-30T07:00:58Z\",\"modified\":\"2016-05-30T07:00:58Z\",\"files_hash\":\"cljhlk2j3l2kj34hlke18\",\"language\":\"ruby\",\"title\":\"Some weird hello world message\",\"public\":false,\"owner\":\"kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k\",\"files\":[{\"name\":\"Some-weird-hello-world-message.rb\",\"content\":\"puts \\\"Some weird hello world message.\\\"\\r\\n\"}]}"
require 'json'
JSON.parse response
# output:
# {"id"=>"a3adasfaf3", "url"=>"https://someurl/a3adasfaf3", "created"=>"2016-05-30T07:00:58Z", "modified"=>"2016-05-30T07:00:58Z", "files_hash"=>"cljhlk2j3l2kj34hlke18", "language"=>"ruby", "title"=>"Some weird hello world message", "public"=>false, "owner"=>"kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k", "files"=>[{"name"=>"Some-weird-hello-world-message.rb", "content"=>"puts \"Some weird hello world message.\"\r\n"}]}
response["name"] # => a3adasfaf3
You need to parse it with JSON.parse
Example:
parsed_hash = JSON.parse res.body
Result:
{
"id" => "a3adasfaf3",
"url" => "https://someurl/a3adasfaf3",
"created" => "2016-05-30T07:00:58Z",
"modified" => "2016-05-30T07:00:58Z",
"files_hash" => "cljhlk2j3l2kj34hlke18",
"language" => "ruby",
"title" => "Some weird hello world message",
"public" => false,
"owner" => "kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k",
"files" => [
[0] {
"name" => "Some-weird-hello-world-message.rb",
"content" => "puts \"Some weird hello world message.\"\r\n"
}
]
}
To access the id:
parsed_hash['id']
To access the url:
parsed_hash['url']
Want to access it by symbols ?
parsed_hash = JSON.parse(res.body).symbolize_keys
You can now access id and url by parsed_hash[:id] and parsed_hash[:url]

Rails: Empty params when do ajax post with content-type = application/json

I used Backbone as Javascript framework for my new project. However, When I invoke save() on a Model , Rails server just can't parse it to the params hash
Javascript
user new Project.Models.User({email : "nqtien310#gmail.com"})
user.save()
Rails server
puts params
=> {"action"=>"create", "controller"=>"users"}
puts request.raw_post
=> "{\"email\":\"nqtien310#gmail.com\"}"
Then I tried to set Backbone.emulateJSON to true
Javascript
Backbone.emulateJSON = true
and Rails can parse the post data to params now, but not the expected data
puts params
=> {"model"=>"{\"email\":\"nqtien310#gmail.com\"}", "action"=>"create", "controller"=>"users"}
Well, after a long research , I figure it out that inside of my profiles' initialize/mime_types.rb , they added
Mime::Type.register "application/json", :mobile
Dig into a bit , I can see that Rails uses the mime types to parse the request body , in this case , application/json is overriden , and Rails can't use the Json parse strategy to parse the request body into params hash, that's why it's empty
Backbone.emulateJSOn will set another content-type instead of application/json, that's why Rails still can understand this Mime Type, and has correspond parse strategy for it , but since it's not the JSON strategy , so the params is not in JSON format
Json parse strategy ( from Rails source )
when :json
data = request.deep_munge ActiveSupport::JSON.decode(request.body)
request.body.rewind if request.body.respond_to?(:rewind)
data = {:_json => data} unless data.is_a?(Hash)
data.with_indifferent_access

Create record example for Quickbooks Online and Intuit Anywhere using Ruby and httparty?

Can someone post an example of creating a record in quickbooks online / intuit anywhere, using ruby and httparty?
I am working on an integration to a ruby on rails app using intuit anywhere, and am running into an issue with my POST request when attempting to create a new record. I have been able to successfully retrieve data (customers) using a POST command that doesn't require XML data in the body of the request, but am running into trouble when trying to create new records that have required fields that need to be passed in XML in the body of the request.
I get the same flavor of error in any entity for which I try to create a record for: an invalid or missing required field. It seems to me that the XML in the body (where the data for the required fields is added) is either being ignored (incorrect formatting?) or is not being attached.
I was hoping the someone else familiar with ruby could post an example of a record creation using httparty. If I could see how to correctly pass the XML using httparty, I can fix my problem myself.
I have been using the customer.com example (https://code.intuit.com/integration/viewvc/viewvc.cgi/IntuitAnywhere-Ruby/customer.com/?root=intuitanywhere&system=exsy1003) mostly as posted, with a few irrelevant modifications needed to get it to work in Rails 3.1. I am using the data pull and handling provided in the example, which looks like a pretty standard API wrapper built using httparty.
I am using a pull similar to the one found in the company_controller customers method. Here are two different ways I have tried submitting the XML:
#########################################
#Example 1 - XML
e = #company.intuit_token.post("https://qbo.intuit.com/qbo1/resource/account/v2/#{#company.realm}",
{ :body =>
"<Account xmlns:ns2=\"http://www.intuit.com/sb/cdm/qbo\" xmlns=\"http://www.intuit.com/sb/cdm/v2\">
<Name>Test Account 2</Name>
<Desc>Test Account</Desc>
<Subtype>Savings</Subtype>
<AcctNum>5001</AcctNum>
<OpeningBalanceDate>2010-05-14</OpeningBalanceDate>
</Account>",
:headers => {
"Content-Type" => "application/xml"
}}
)
#########################################
#Example 2 - hash
e = #company.intuit_token.post("https://qbo.intuit.com/qbo1/resource/account/v2/#{#company.realm}",
{ :body => {
:Account => {
:Name => "Loan Account 2",
:Desc => "Loac Account 2",
:Subtype => "Savings",
:AcctNum => "5001",
:OpeningBalanceDate => "2011-04-22"
}
},
:headers => {
"Content-Type" => "application/xml"
}}
)
I incorrectly assumed the customer.com example provided by intuit was using the httparty gem to make the POST call, so I was using the wrong syntax. They are actually using the OAuth gem's POST call, who's syntax can be found here: http://oauth.rubyforge.org/rdoc/classes/OAuth/AccessToken.html
I also had to modify the headers to get the Intuit Anywhere service to accept the XML body. Here is the code that finally worked for me to create a record in quickbooks online using intuit anywhere:
e = #company.intuit_token.post("https://qbo.intuit.com/qbo1/resource/account/v2/#{#company.realm}", "<Account xmlns:ns2=\"http://www.intuit.com/sb/cdm/qbo\" xmlns=\"http://www.intuit.com/sb/cdm/v2\"><Name>Test Account </Name><Desc>Test Account</Desc><Subtype>Savings</Subtype><AcctNum>5002</AcctNum><OpeningBalanceDate>2010-05-14</OpeningBalanceDate></Account>", {"Content-Type" => "application/xml", "standalone" => "yes", "encoding" => "UTF-8"})

What is the right way to set WWW-Authenticate header in rails response?

What is the right way to set WWW-Authenticate header in rails response?
Currently I do it this way:
headers["WWW-Authenticate"] = %(Basic realm="My Realm")
render :json => {:message =>I18n.t("errors.messages.authorization_error")}, :status => :unauthorized
I think that there is a more simple way to set this header using rails api. Without accessing header dictionary directly.
There is nothing wrong with what you are doing, but rails does have HTTP authenication baked in. Please see this link: http://apidock.com/rails/ActionController/HttpAuthentication/Basic/ControllerMethods/authenticate_or_request_with_http_basic

How to post JSON data in rails 3 functional test

I plan to use JSON data in both request and response in my project and having some problems in testing.
After searching for a while, I find the following code which uses curl to post JSON data:
curl -H "Content-Type:application/json" -H "Accept:application/json" \
-d '{ "foo" : "bar" }' localhost:3000/api/new
In the controller I can access the JSON data simply using params[:foo] which is really easy. But for functional testing, I only find post and xhr (alias for xml_http_request).
How can I write functional test in rails to achieve the same effect as using curl? Or should I do test in other ways?
Here's what I've tried. I find the implementation for xhr in action_controller/test_case.rb, and tried to add jhr method simply changing 'Conetent-Type' and 'HTTP_ACCEPT'. (Added in test/test_helpers.rb.)
def json_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
#request.env['Content-Type'] = 'Application/json'
#request.env['HTTP_ACCEPT'] ||= [Mime::JSON, Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
__send__(request_method, action, parameters, session, flash).tap do
#request.env.delete 'Content-Type'
#request.env.delete 'HTTP_ACCEPT'
end
end
alias jhr :json_http_request
I used this in the same way as xhr, but it does not work. I inspected the #response object and sees the body is " ".
I also find one similar question on Stack Overflow but it's for rails 2 and the answer for posting raw data does not work in rails 3.
As of Rails 5, the way to do this is:
post new_widget_url, as: :json, params: { foo: "bar" }
This will also set the Content-type header correctly (to application/json).
I found that this does exactly what I want – post JSON to a controller's action.
post :create, {:format => 'json', :user => { :email => "test#test.com", :password => "foobar"}}
Just specify appropriate content type:
post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json'
Json data should go as a string, not as a Hash.
Looking at stack trace running a test you can acquire more control on request preparation:
ActionDispatch::Integration::RequestHelpers.post => ActionDispatch::Integration::Session.process =>
Rack::Test::Session.env_for
Specifying :format does not work because request go as 'application/x-www-form-urlencoded' and json isn't parsed properly processing a request body.
Assuming you have a controller named api, a method named new, and you're in the test for the api controller:
#request.env["RAW_POST_DATA"] = '{ "foo" : "bar" }'
post :new
did the trick for me.
Here is a snippet that let me post json data to test my own app. rails 3
port = Rails.env.production? ? 80 : 3000
uri = URI.parse( Rails.application.routes.url_helpers.books_url(:host => request.host, :port => port, :format => :json) )
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.content_type = 'application/json'
request.body = #json_data
response = http.request( request )
#result = response.body
Hope this helps others
As #taro suggests in a comment above, the syntax that works for me in functional and integration tests is:
post :create, {param1: 'value1', param2: 'value2', format: 'json'}
(The curly braces aren't always necessary, but sometimes it doesn't work if they're missing, so I always add them.)
Here's what params and request.format look like for a post of that sort:
params:
{"param1"=>"value1", "param2"=>"value2", "format"=>"json", "controller"=>"things", "action"=>"create"}
request.format:
application/json
The best answer I can come up with to this is you don't
Whether or not it was intentional it s maybe good that rails doesn't implement this for you.
In functional tests you really want to just test your controller and not rails method of deserialization or even that routing and mime detection are all setup correctly, those all fall under an IntegrationTest.
So for your controllers, don't pass JSON just pass your params hash like you normally would. Maybe adding :format as an argument as well if you need to check that and respond differently.
If you want to test the full stack move to an IntegrationTest

Resources