Ruby Grape::Request convert to string and store in database - ruby

How would you convert the Grape::Request object to a string in order to store it's contents in the database? I tried
request.to_s and only get #<Grape::Request:0x007f7fd34605c8>
I also tried
request.to_json and get this IOError Exception: not opened for reading

Perhaps the Grape::Endpoint#request method is what you're looking for, although there are others like env that may have more or less of what you need.
I tried it by putting it in the Alongside Sinatra (or other frameworks) example given in the docs:
require 'grape'
require 'sinatra/base'
class API < Grape::API
get :hello do
{req: request}
end
end
class Web < Sinatra::Base
get '/' do
"Hello world."
end
end
run Rack::Cascade.new [API, Web]
and on calling it:
$ [2015-07-22 08:21:17] INFO WEBrick 1.3.1
[2015-07-22 08:21:17] INFO ruby 2.2.2 (2015-04-13) [x86_64-darwin13]
[2015-07-22 08:21:17] INFO WEBrick::HTTPServer#start: pid=30420 port=9292
curl http://localhost:9292/hello
127.0.0.1 - - [22/Jul/2015:08:21:19 +0100] "GET /hello HTTP/1.1" 200 3665 0.0389
{:req=>#<Grape::Request:0x007f9971425d08 #env={"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/hello", "QUERY_STRING"=>"", "REMOTE_ADDR"=>"127.0.0.1", "REMOTE_HOST"=>"localhost", "REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"http://localhost:9292/hello", "SCRIPT_NAME"=>"", "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"9292", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)", "HTTP_USER_AGENT"=>"curl/7.30.0", "HTTP_HOST"=>"localhost:9292", "HTTP_ACCEPT"=>"*/*", "rack.version"=>[1, 3], "rack.input"=>#<Rack::Lint::InputWrapper:0x007f99711d6458 #input=#<StringIO:0x007f99711e52f0>>, "rack.errors"=>#<Rack::Lint::ErrorWrapper:0x007f99711d6430 #error=#<IO:<STDERR>>>, "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, "rack.url_scheme"=>"http", "rack.hijack?"=>true, "rack.hijack"=>#<Proc:0x007f99711dc3d0#/Users/iainb/Projects/Test/31551252/vendor.noindex/ruby/2.2.0/gems/rack-1.6.4/lib/rack/lint.rb:525>, "rack.hijack_io"=>nil, "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_PATH"=>"/hello", "sinatra.commonlogger"=>true, "rack.tempfiles"=>[], "rack.routing_args"=>{:route_info=>#<Grape::Route:0x007f997106fcb8 #options={:params=>{}, :prefix=>nil, :version=>nil, :namespace=>"/", :method=>"GET", :path=>"/hello(.:format)", :compiled=>/\A\/hello(?:\.(?<format>[^\/.?]+))?\Z/, :settings=>{}}>}, "api.endpoint"=>#<Grape::Endpoint:0x007f9971497750 #inheritable_setting=#<Grape::Util::InheritableSetting:0x007f9971157040 #route={:saved_declared_params=>[], :saved_validations=>[]}, #api_class={}, #namespace=#<Grape::Util::InheritableValues:0x007f9971156820 #inherited_values={}, #new_values={}>, #namespace_inheritable=#<Grape::Util::InheritableValues:0x007f9971156780 #inherited_values=#<Grape::Util::InheritableValues:0x007f99711c5860 #inherited_values={}, #new_values={}>, #new_values={:default_error_status=>500}>, #namespace_stackable=#<Grape::Util::StackableValues:0x007f9971156618 #inherited_values=#<Grape::Util::StackableValues:0x007f99711c57c0 #inherited_values={}, #new_values={}, #froozen_values={}>, #new_values={}, #froozen_values={}>, #point_in_time_copies=[], #parent=#<Grape::Util::InheritableSetting:0x007f99711c5950 #route={}, #api_class={}, #namespace=#<Grape::Util::InheritableValues:0x007f99711c58d8 #inherited_values={}, #new_values={}>, #namespace_inheritable=#<Grape::Util::InheritableValues:0x007f99711c5860 #inherited_values={}, #new_values={}>, #namespace_stackable=#<Grape::Util::StackableValues:0x007f99711c57c0 #inherited_values={}, #new_values={}, #froozen_values={}>, #point_in_time_copies=[], #parent=nil>>, #options={:method=>["GET"], :path=>[:hello], :for=>API, :route_options=>{:params=>{}}}, #source=#<Proc:0x007f99711c5450#/Users/iainb/Projects/Test/31551252/config.ru:5>, #block=#<Proc:0x007f9971143cc0#/Users/iainb/Projects/Test/31551252/vendor.noindex/ruby/2.2.0/gems/grape-0.12.0/lib/grape/endpoint.rb:47>, #namespace="/", #routes=[#<Grape::Route:0x007f997106fcb8 #options={:params=>{}, :prefix=>nil, :version=>nil, :namespace=>"/", :method=>"GET", :path=>"/hello(.:format)", :compiled=>/\A\/hello(?:\.(?<format>[^\/.?]+))?\Z/, :settings=>{}}>], #env={...}, #header={}, #request=#<Grape::Request:0x007f9971425d08 ...>, #params=#<Hashie::Mash>, #headers={"User-Agent"=>"curl/7.30.0", "Host"=>"localhost:9292", "Accept"=>"*/*", "Version"=>"HTTP/1.1"}, #cookies=#<Grape::Cookies:0x007f99713be090 #cookies={}, #send_cookies={}>>, "api.format"=>:txt, "rack.request.query_string"=>"", "rack.request.query_hash"=>{}, "rack.request.cookie_hash"=>{}}, #params=#<Hashie::Mash>, #headers={"User-Agent"=>"curl/7.30.0", "Host"=>"localhost:9292", "Accept"=>"*/*", "Version"=>"HTTP/1.1"}>}%

Related

Sinatra Ruby app one line log per request with custom info

I have one app that is a Sinatra app. I would like to have the log of each request on one line, Currently only 1 line per request is shown(the request itself). But I want to append custom info to it.
This is my current line:
[02/Feb/2018:11:52:32 +0000] "GET /feed/name.csv HTTP/1.0" 200 - 0.1620
2400:gh654:32:6532:0:0:a43e:404f, 0.0.0.0:2017 - - [05/Feb/2018:13:32:48 +0000] "HEAD / HTTP/1.0" 404 18 0.0676
2400:gh654:32:6532:0:0:a43e:414d, 0.0.0.0:2017 - - [05/Feb/2018:13:32:48 +0000] "HEAD / HTTP/1.0" 404 18 0.0041
I want to transform it in something like:
INFO 2018-03-02T14:03:36Z [main] [066843] [8a6e846f-45b7-433d-9d98-21c8c0766ad7] method=GET path= /some/path.csv format=csv action=action_name status=200 duration=459.97 view=154.94 db=172.96 user=user_id ip=user_id on=protocol_used agent=agent_used params=params_used
In the past to do this in rails applications I have used lograge but it seems it is not supported by sinatra apps.
Have you guys ever had to append custom info to the sinatra logs?
This is my configuration for logging:
configure do
enable :logging
file = File.new("#{RAILS_ROOT}/log/#{settings.environment}.log", 'a+')
file.sync = true
use Rack::CommonLogger, file
set :show_exceptions, true
set :logging, true
ActiveRecord::Base.logger = Logger.new("#{RAILS_ROOT}/log/#{settings.environment}.log")
end

Using Rack to run a React application is not working as it should

My idea is using Rack to load a web application separated in two parts. This is the structure:
my_app
|______api
| |______poros
|
|______fe
| |______build
| |______node_modules
| |______package.json
| |______public
| | |______ index.html
| | ...
| |______README.md
| |______src
| |______index.js
| ...
|______config.ru
The fe part (which stands for front-end) is a React application created with create-react-app. I've built it with
npm run build
and then its static optimized build is under my_app/fe/build directory.
This is my my_app/config.ru:
#\ -w -p 3000
require 'emeraldfw'
use Rack::Reloader, 0
use Rack::ContentLength
run EmeraldFW::Loader.new
And this is my EmeraldFW::Loader class, which is part of a gem installed and running fine.
module EmeraldFW
class Loader
def call(env)
path_info = (env['PATH_INFO'] == '/') ? '/index.html' : env['PATH_INFO']
extension = path_info.split('/').last.split('.').last
file = File.read("fe/build#{path_info}")
[200,{'Content-Type' => content_type[extension]},[file]]
end
def content_type
{
'html' => 'text/html',
'js' => 'text/javascript',
'css' => 'text/css',
'svg' => 'image/svg+xm',
'ico' => 'image/x-icon',
'map' => 'application/octet-stream'
}
end
end
end
As you may see, this is all quite simple. I capture the request with in my EmeraldFW::Loader class and transform its path_info it a bit. If the request is '/' I rewrite it to '/index.html' before doing anything else. In all cases I prepend fe/build to make it load from the static build of the React application.
When I run
rackup config.ru
and load the application at http://localhost:3000 the result is completely fine:
[2017-03-15 21:28:23] INFO WEBrick 1.3.1
[2017-03-15 21:28:23] INFO ruby 2.3.3 (2016-11-21) [x86_64-linux]
[2017-03-15 21:28:23] INFO WEBrick::HTTPServer#start: pid=11728 port=3000
::1 - - [15/Mar/2017:21:28:27 -0300] "GET / HTTP/1.1" 200 386 0.0088
::1 - - [15/Mar/2017:21:28:27 -0300] "GET /static/css/main.9a0fe4f1.css HTTP/1.1" 200 623 0.0105
::1 - - [15/Mar/2017:21:28:27 -0300] "GET /static/js/main.91328589.js HTTP/1.1" 200 153643 0.0086
::1 - - [15/Mar/2017:21:28:28 -0300] "GET /static/media/logo.5d5d9eef.svg HTTP/1.1" 200 2671 0.0036
::1 - - [15/Mar/2017:21:28:28 -0300] "GET /static/js/main.91328589.js.map HTTP/1.1" 200 1705922 0.1079
::1 - - [15/Mar/2017:21:28:28 -0300] "GET /static/css/main.9a0fe4f1.css.map HTTP/1.1" 200 105 0.0021
As you may see, all resources are loading correctly, with the correct mime types. But it happens that my default React logo, which should be spinning in my app frontpage, is not there! As if it wasn't loaded.
The big picture of all this is having this rack middleware loading the React front-end of the app and, at the same time, redirecting correctly the api requests made with fetch from the front-end to the poros (Plain Old Ruby Objects) which are the API part.
The concept is quite simple. But I just can't understand why this specific resource, the svg logo, is not loading.
It was all a matter of wrong mime type, caused by a typo.
It may be clearly seen in my question that I wrote:
def content_type
{
'html' => 'text/html',
'js' => 'text/javascript',
'css' => 'text/css',
'svg' => 'image/svg+xm', # <== Here is the error!!!
'ico' => 'image/x-icon',
'map' => 'application/octet-stream'
}
end
when the correct mime type for SVG files is 'image/svg-xml', with an 'l'...
This was making the browser ignore the file received and so it won't display it correctly.

why is my plivo api call returning an error?

I am using the plivo search number api to list telephone numbers by selected parameters.
The ruby code is:
get '/search_numbers' do
p = RestAPI.new(AUTH_ID, AUTH_TOKEN)
params = {'country_iso' => 'GB'}
response = p.search_phone_number(params)
end
and the error I receive is:
88.106.106.78 - - [22/Jan/2015:15:02:59 +0000] "GET /search_numbers HTTP/1.0" 200 - 1.7485
2015-01-22 15:02:59 +0000: Read error: #<NoMethodError: undefined method `bytesize' for ["api_id", "c025f0cc-a247-11e4-b153-22000abcaa64"]:Array>
I simply cannot figure out what is wrong. I can see no typos, the parameter that is passed is correct and in the correct format and the function is the right function to use.
Help, please!

Open remote URL returns empty string?

I was using the following code snippet, which was working, to fetch the JSON response from the Spotify oEmbed API.
I was doing this:
response = JSON.parse(open("https://embed.spotify.com/oembed/?url=http://open.spotify.com/album/5Mxj65mCzxUjDkoqz7JXPJ").read)
But now, this stopped working because:
2.0.0p247 :017 > open("https://embed.spotify.com/oembed/?url=http://open.spotify.com/album/5Mxj65mCzxUjDkoqz7JXPJ").read
=> ""
But, using cURL, I get:
$curl https://embed.spotify.com/oembed/\?url\=http://open.spotify.com/album/5Mxj65mCzxUjDkoqz7JXPJ
{"provider_url":"https:\/\/www.spotify.com","version":"1.0","thumbnail_width":300,"height":380,"thumbnail_height":300,"title":"Illum Sphere - 13. Embryonic","width":300,"thumbnail_url":"https:\/\/d3rt1990lpmkn.cloudfront.net\/cover\/d4f5d8624752eeae3dc8bc3d58e2155d095181c1","provider_name":"Spotify","type":"rich","html":"<iframe src=\"https:\/\/embed.spotify.com\/?uri=spotify:album:5Mxj65mCzxUjDkoqz7JXPJ\" width=\"300\" height=\"380\" frameborder=\"0\" allowtransparency=\"true\"><\/iframe>"}
Any advice?
Try passing the User-Agent:
require 'open-uri'
puts open("https://embed.spotify.com/oembed/?url=http://open.spotify.com/album/5Mxj65mCzxUjDkoqz7JXPJ", "User-Agent" => "Ruby/#{RUBY_VERSION}").read
Result:
{"provider_url":"https:\/\/www.spotify.com","version":"1.0","thumbnail_width":300,"height":380,"thumbnail_height":300,"title":"
Illum Sphere - 13. Embryonic","width":300,"thumbnail_url":"https:\/\/d3rt1990lpmkn.cloudfront.net\/cover\/d4f5d8624752eeae3dc8b
c3d58e2155d095181c1","provider_name":"Spotify","type":"rich","html":"<iframe src=\"https:\/\/embed.spotify.com\/?uri=spotify:al
bum:5Mxj65mCzxUjDkoqz7JXPJ\" width=\"300\" height=\"380\" frameborder=\"0\" allowtransparency=\"true\"><\/iframe>"}

Sinatra, MongoMapper, and Builder wrong number of arguments (1 for 0)

I am getting this error when calling a builder template from sinatra route:
wrong number of arguments (1 for 0)
Sinatra - 1.1.2
Builder - 3.0.0
MongoMapper - 0.8.6
Calling it like this:
get '/current_load.xml' do
#caption = "Load Average"
#sub_caption = "5 minutes"
#time = Performance.where(:NAGIOS_SERVICEDESC => "Current Load").fields(:NAGIOS_LONGDATETIME).all
content_type :xml
builder :current_load
end
the builder file starts off like this:
xml.instruct!
Here's the full trace of the error:
ArgumentError - wrong number of arguments (1 for 0):
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlbase.rb:135:in `to_xs'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlbase.rb:135:in `_escape'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlbase.rb:140:in `_escape_quote'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlmarkup.rb:320:in `_attr_value'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlmarkup.rb:308:in `_insert_attributes'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlmarkup.rb:306:in `each'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlmarkup.rb:306:in `_insert_attributes'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlmarkup.rb:284:in `_special'
/usr/lib/ruby/gems/1.8/gems/builder-3.0.0/lib/builder/xmlmarkup.rb:250:in `instruct!'
/opt/nec/www/nec/views/current_load.builder:1:in `evaluate_source'
If I change Builder to 2.1.2, I receive no error
or
If I take MongoMapper out I receive no error
Sounds like an issue between two gems??
Sinatra 1.1.3 successfully fixed this error.
That is the only change in the environment

Resources