Bad URI Ruby on Rails: is it because long? - html

So I have a website that's fully working, with some URI encoded in the URL.
however, when I try to pass the URL to my chrome browser:
http://somewhere:3000/find/someOne?utf8=%E2%9C%93&search=someThing&choicen=no&querys={%22peopleName%22%3A%22%22%2C%22peopleGroup%22%3A%22%22%2C%22place%22%3A%22%22%2C%22pip%22%3A%22%22%2C%22hw%22%3A%22%22%2C%22somerock%22%3A%22%22%2C%22rocksomerock%22%3A%22%22%2C%22diedAt%22%3A%222016-01-01%20-%202016-12-31%22%2C%22borndAt%22%3A%22%22%2C%22taxRate%22%3A%22%22}
-- it throws me an error in the browser:
Bad Request
bad URI `/find/someOne?utf8=%E2%9C%93&search=someThing&choicen=no&querys={%22peopleName%22%3A%22%22%2C%22peopleGroup%22%3A%22%22%2C%22place%22%3A%22%22%2C%22pip%22%3A%22%22%2C%22hw%22%3A%22%22%2C%22somerock%22%3A%22%22%2C%22rocksomerock%22%3A%22%22%2C%22diedAt%22%3A%222016-01-01%20-%202016-12-31%22%2C%22borndAt%22%3A%22%22%2C%22taxRate%22%3A%22%22}'.
WEBrick/1.3.1 (Ruby/1.9.3/2014-11-13) at somewhere.com:3000
Also shows [2016-07-04 18:11:31] ERROR bad URI in the rails console
Versions:
rails3
Ruby 1.9.3
Any idea how to get it working? Is it because the { and } in the URI or because it is too long?

Parse the path in the controller upon incoming request, using Rack::Utils#parse_nested_query, see: http://www.rubydoc.info/github/rack/rack/master/Rack/Utils.parse_nested_query
# config/routes.rb
get '/find/someOne/*str' => 'find#someOne'
# app/controllers/find_controller.rb
class FindController < ApplicationController
def someOne
custom_params = Rack::Utils.parse_nested_query(request.env['ORIGINAL_FULLPATH'])
querys_hash = JSON.parse(custom_params["querys"])
end
end
Example via console:
$ bundle exec rails c
Running via Spring preloader in process 31944
Loading development environment (Rails 5.0.0)
irb(main):001:0> custom_params = Rack::Utils.parse_nested_query "utf8=%E2%9C%93&search=someThing&choicen=no&querys={%22peopleName%22%3A%22%22%2C%22peopleGroup%22%3A%22%22%2C%22place%22%3A%22%22%2C%22pip%22%3A%22%22%2C%22hw%22%3A%22%22%2C%22somerock%22%3A%22%22%2C%22rocksomerock%22%3A%22%22%2C%22diedAt%22%3A%222016-01-01%20-%202016-12-31%22%2C%22borndAt%22%3A%22%22%2C%22taxRate%22%3A%22%22}"
=> {"utf8"=>"✓", "search"=>"someThing", "choicen"=>"no", "querys"=>"{\"peopleName\":\"\",\"peopleGroup\":\"\",\"place\":\"\",\"pip\":\"\",\"hw\":\"\",\"somerock\":\"\",\"rocksomerock\":\"\",\"diedAt\":\"2016-01-01 - 2016-12-31\",\"borndAt\":\"\",\"taxRate\":\"\"}"}
irb(main):002:0> querys_hash = JSON.parse custom_params["querys"]
=> {"peopleName"=>"", "peopleGroup"=>"", "place"=>"", "pip"=>"", "hw"=>"", "somerock"=>"", "rocksomerock"=>"", "diedAt"=>"2016-01-01 - 2016-12-31", "borndAt"=>"", "taxRate"=>""}

Related

ActionMailer ArgumentError - SMTP-AUTH requested but missing secret phrase

I am using Yandex Connect (SMTP) as a method to send emails from my Rails 5 JSON API app.
Here's the setup:
Rails.application.configure do
config.action_mailer.delivery_method = :smtp
config.action_mailer.raise_delivery_errors = true
config.action_mailer.smtp_settings = {
address: 'smtp.yandex.com',
port: 25,
domain: ENV['MAIL_DOMAIN'],
user_name: ENV['MAIL_USER'],
password: ENV['MAIL_PASSWORD'],
authentication: 'plain',
enable_starttls_auto: true
}
end
I also have config.action_mailer.default_url_options = { host: ENV['MAIL_DOMAIN'] } set in my application.rb
On heroku with the right credentials it works just fine. But when I try to run the same config localy and send an email, I get ArgumentError - SMTP-AUTH requested but missing secret phrase.
What could be wrong
1) Make sure the environment variables are really there, e.g. bundle exec rails console, puts ENV.inspect
2) Make sure the credentials are correct
3) Restart your development server after you've modified your environment. This includes spring stop.

rails 5 api returns 301 from PORO

I have a Rails 5.0.0.1 API application that needs to return a simple PORO as json. I am using gem 'responders', '~> 2.3.0'
The object constructs correctly and works properly in the Rails server. It has only 4 attributes that are needed by the front-end.
The serializer is:
class WebsiteConfigSerializer < ActiveModel::Serializer
attributes :force_first_user_to_be_admin, :allows_delete_of_last_admin,
:is_private_website, :invite_only
end
The controller show method (the only method in the controller) is:
def show
config = WebsiteConfig.new
puts "Config: #{config.to_json}"
respond_to do |format|
format.json {render( json: config, status: 200 ) }
end
end
The log shows the request output, including the debugging puts statement:
Started GET "/config.json" for 127.0.0.1 at 2016-09-03 18:23:32 -0400
Processing by WebsiteConfigController#show as JSON
Config: {"force_first_user_to_be_admin":true, "allows_delete_of_last_admin":false, "is_private_website":true, "invite_only":true}
[active_model_serializers] Rendered WebsiteConfigSerializer with ActiveModelSerializers::Adapter::Attributes (0.13ms)
Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.0ms)
as expected.
The output of cURL is:
curl -sb -H "Accept:application/json" -H "Content-Type:application/json" http://localhost:3000/config
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
This is NOT what I expected.
wget output is EMPTY (0 bytes). Also not what I expected.
Obviously I am missing something. Any help will be appreciated.
Your request has been redirected, check if you have some authentication code like requiring login or something else, then added them to the curl command

GAE Python AssertionError: write() argument must be string

I am using Sublime Text 2 as my editor and creating a new Google App Engine project.
EDIT: I am running this code through localhost. I get this error on when viewing the app on appspot:
Status: 500 Internal Server Error Content-Type: text/plain Content-Length: 59 A server error occurred. Please contact the administrator.
I have this code:
import webapp2 as webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class IndexPage(webapp.RequestHandler):
def get(self):
self.response.out.write('Hello, World!')
app = webapp.WSGIApplication([('/.*', IndexPage)], debug = True)
def main():
run_wsgi_app(app)
if __name__ == '__main__':
main()
It causes an AssertionError:
File "C:\Python27\lib\wsgiref\handlers.py", line 202, in write
assert type(data) is StringType,"write() argument must be string"
AssertionError: write() argument must be string
What does the error mean and what could be causing it?
GAE was not recognizing my app.yaml file properly. Once I fixed that, it worked. Thanks

Logging errors in a grails application in the logs

When my Grails application crashes, it shows the error and the stacktrace on the error page because the error.gsp page has the following snippet <g:renderException exception="${exception}" />. However nothing gets logged in the log file.
How can I change this? because for the production application I plan to remove the renderException because I don't want users to see the entire stacktrace.
My log4j settings are as follows:
appenders {
rollingFile name:'catalinaOut', maxFileSize:1024, fileName:"${System.properties.getProperty('catalina.home')}/logs/mylog.log"
}
root {
error 'catalinaOut'
debug 'catalinaOut'
additivity = true
}
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages', // GSP
'org.codehaus.groovy.grails.web.sitemesh', // layouts
'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
'org.codehaus.groovy.grails.web.mapping', // URL mapping
'org.codehaus.groovy.grails.commons', // core / classloading
'org.codehaus.groovy.grails.plugins', // plugins
'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate',
'grails.app'
debug 'grails.app'
}
I'm running the app in development as grails run-app
I use these settings for console and file based logging. You can remove stdout if you don't want/need console. Just copy all your error classes in the corresponding list.
log4j = {
def loggerPattern = '%d %-5p >> %m%n'
def errorClasses = [] // add more classes if needed
def infoClasses = ['grails.app.controllers.myController'] // add more classes if needed
def debugClasses = [] // add more classes if needed
appenders {
console name:'stdout', layout:pattern(conversionPattern: loggerPattern)
rollingFile name: "file", maxFileSize: 1024, file: "./tmp/logs/logger.log", layout:pattern(conversionPattern: loggerPattern)
}
error stdout: errorClasses, file: errorClasses
info stdout: infoClasses, file: infoClasses
debug stdout: debugClasses, file: debugClasses
}

Sinatra access-control-allow-origin for sinatra public folder

How do I set up Sinatra so that static files in the public folder
are returned with the response Access-Control-Allow-Origin = "*" ?
Have a look at this question here: Sinatra OPTIONS HTTP Verb. It's implemented in sinatra now so you don't have to hack around it.
If that doesn't help take a look at this blog post: Cross Origin Resource Sharing with Sinatra, and its repo at github: sinatra-corss_origin
Although the simplest way to do it should work just by adding this:
response['Access-Control-Allow-Origin'] = 'http://whatever.org'
before the return value in your route.
get '/foo' do
headers 'Access-Control-Allow-Origin' => 'http://example.com'
'hello world'
end
There's also a nice extension for cross origin sharing:
https://github.com/britg/sinatra-cross_origin
require 'sinatra'
require 'sinatra/cross_origin'
# To enable cross origin requests for all routes:
configure do
enable :cross_origin
end
# To only enable cross origin requests for certain routes:
get '/cross_origin' do
cross_origin
"This is available to cross-origin javascripts"
end
I did this on a server side, my file was called server.rb:
before do
content_type :json
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST']
end
This setup works for me:
Gemfile:
# Gemfile
gem 'sinatra'
gem 'sinatra-cross_origin'
Sinatra App:
# app.rb
require 'sinatra'
require 'sinatra/cross_origin'
class MyApp < Sinatra::Base
set :bind, '0.0.0.0'
configure do
#This is enable cross on the server
enable :cross_origin
end
#This before blocks gets invoked on every request and
#the (*) mark tells your server that share the resource with anyone,
#if you want to share it with specific domain you can mention the domain/s
#by removing the asterisk sign.
before do
response.headers['Access-Control-Allow-Origin'] = '*'
end
# routes...
options "*" do
response.headers["Allow"] = "GET, PUT, POST, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Authorization,
Content-Type, Accept, X-User-Email, X-Auth-Token"
response.headers["Access-Control-Allow-Origin"] = "*"
200
end
end
The options block described above sends a 200 response to the preflight request sent by the browser. Then the browser makes the CORS request. In response to this request, the server sends Access-Control-Allow-Origin = * in response headers.
If we want only a specific domain to access the resources:
before do
response.headers['Access-Control-Allow-Origin'] = 'http://example.com'
end
this solution works for me and is based on an answer on a similar question How to add "Access-Control-Allow-Origin" headers to API Response in Ruby
get '/' do
response['Access-Control-Allow-Origin'] = '*'
"asdf" # return "asdf"
end