I'm trying to deploy my sinatra on Heroku https://www.heroku.com/home
I was successful before I tried post method which gave me 404
Get methods work fine:
here is the example of the code:
get '/getPriceList' do //no error, everything works fine
content_type :json, charset: 'utf-8'
today_menu.to_json
end
post '/makeOrder', provides: :json do //error NOT FOUND
data = request.env['rack.input'].read
parsed_data = JSON.parse data.force_encoding('UTF-8')
if User.where(:name => parsed_data['userName']).first.nil?
current = Time.now
fixed = Time.local(current.year, current.month, current.day, 18, 40, 0)
if current > fixed
ObedResponse.new(data, false, 'Vi ne uspeli').to_json
else
#user = User.create(:name => parsed_data['userName'])
#some stuff
end
ObedResponse.new(data, true, "").to_json
end
else
ObedResponse.new(data, false, 'Сегодня вы уже заказали').to_json
end
Can someone tell me why I'm getting this error and how to make the thing work?
PS: I don't have this error while deploying locally using
bundle exec ruby obed.rb -e production
to start
I was in the wrong branch when I commited into Heroku. Changing the branch to master solved the issue.
Related
This one is driving me nuts.
I have two websites who have to talk to each other trough JSONP.
Site A checks in its database if some value is present and returns json data {"result":"Found in library"} if found.
When doing a cURL from the command line, I get my data as expected.
Doing a Ajax call from site B, I can see in the logging of site A that the request is handled correct, but site B complains about "Unexpected end of data at line 1" The inspector shows me no data at all, so I assume that is the problem. Where did the data go?
As I don't want the inner workings of the Ajax call to be reveiled, I want to do it in the Ruby controller with a Net::HTTP call.
Again, I can see in the logging of site A that the call is handled correct and returns the result.
This time, Ruby logging shows:
Errno::EPROTONOSUPPORT (Failed to open TCP connection to xx.domain.com:443 (Protocol not supported - socket(2) for "xx.domain.com" port 443)):
My controller in site B:
def query
respond_to do |format|
format.js {
# Submit Ajax call
uri = URI(base_url + "/data_subjects/query.json")
data = {
key: api_key,
parmA: params[:parmA],
parmB: params[:parmB],
}
uri.query = URI.encode_www_form(data)
logger.info("QUERY: #{uri.inspect}")
res = Net::HTTP.get_response(uri)
render :json, JSON.parse(res)
}
end
end
My controller in site A:
def query
respond_to do |format|
format.json {
.... Do some stuff
if $rc == 1
render json: {:result => I18n.t("result_found")}, status: :ok , :layout => false
else
render json: {result: I18n.t("result_not_found")}, status: 404, :layout => false
end
}
end
As I said, using cURL everything looks okay, but with either jQuery or Ruby it fails.
UPDATE
Okay, found it!
As it turns out, you need to specify ":callback => params[:callback]" to the json response:
render json: {:result => I18n.t("result_found")}, :callback => params[:callback], status: :ok , :layout => false
Problem was triggered by not having IPv6 support in the FreeBSD jail in which the calling process runs. And the server which was called only has IPv6 connectivity.
I have an application in production with ElasticSearch. (It works) but now I can add searchkick gem instead use only elasticsearch.
For this I added the following:
In my Gemfile added:
gem 'elasticsearch-model'
gem 'elasticsearch-rails'
gem 'searchkick'
In my config/initializers/elasticsearch.rb (I'm using Amazon Elasticsearch Service for production. Ok I know this is bad practices but I'll go change this for Environment variables)
if Rails.env == "production"
Elasticsearch::Model.client = Elasticsearch::Client.new url: 'https://xxxxxxxx.xxxxxxx.amazonaws.com/'
else
Elasticsearch::Model.client = Elasticsearch::Client.new url: 'http://localhost:9200/'
end
in models/product.rb
require 'elasticsearch/model'
class Product < ActiveRecord::Base
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
searchkick
#currently use this function for search. (It works)
scope :searching, ->(query) { __elasticsearch__.search(query).records }
end
but now when I try to use in the server:
Product.search("foobar") #before run: rails c production
Show me the next message: Faraday::ConnectionFailed: Connection refused - connect(2)
After that I try this
rake searchkick:reindex:all RAILS_ENV=production
And I got the same message. Any idea for this ?
After I finished write this post I read this: Searchkick with ElasticSearch returns "Faraday::ConnectionFailed: execution expired"
in config/initializers/elasticsearch.rb
if Rails.env == "production"
url = 'http://myelasticsearch-xyz-foobar.amazonaws.com'
Elasticsearch::Model.client = Elasticsearch::Client.new url: url
Searchkick.client = Elasticsearch::Client.new(hosts: url, retry_on_failure: true, transport_options: {request: {timeout: 250}})
else
url = 'http://localhost:9200/'
Elasticsearch::Model.client = Elasticsearch::Client.new url: url
Searchkick.client = Elasticsearch::Client.new(hosts: url, retry_on_failure: true, transport_options: {request: {timeout: 250}})
end
After refactoring and clean this code I got this:
Elasticsearch::Model.client = Elasticsearch::Client.new url: env['RAILS_ENV']
Searchkick.client = Elasticsearch::Client.new(hosts: env['RAILS_ENV'], retry_on_failure: true, transport_options: {request: {timeout: 250} })
I hope this explanation works for others
I found the above answer to get me 95% of the way there. I followed Nelson's advice and created an Elasticsearch initializer which eliminated the Faraday::ConnectionFailed (Connection refused - connect(2) for "localhost" port 9200):
However I still had to reindex and migrate my Heroku DB.
heroku run rake searchkick:reindex CLASS=YOUR CLASS NAME
then heroku run rake db:migrate
Hope that clarifies for any Heroku newbies such as myself who got stuck on the last part.
If you are using gem 'searchkick' just add the below line in /config/initializers/elasticsearch.rb
ENV["ELASTICSEARCH_URL"] = "http://myelasticsearch-xyz-foobar.amazonaws.com:port"
Im working in a small sinatra app that i want it to fetch a json file for latter use.
Using browser, i can access the json just OK, also on irb:
1.9.2p320 :001 > require 'open-uri'
=> true
1.9.2p320 :002 > metrics = open "http://foo-bar.com:8085/metrics/index.json"
=> #<File:/tmp/open-uri20130529-12715-1upc3bm>
1.9.2p320 :003 > metrics.read
=> "[\"carbon.agents.io-a.avgUpdateTime\", \"carbon.agents.io-a.cache.overflow\", \"carbon.agents.io-a.cache.queries\", \"carbon.agents.io-a.cache.queues\", \"carbon.agents.io-a.cache.size\", \"carbon.agents.io-a.committedPoints\", \"carbon.agents.io-a.cpuUsage\", \"carbon.agents.io-a.creates\", \"carbon.agents.io-a.errors\", \"carbon.agents.io-a.memUsage\" ...
it returns me the desired file.
But when i try to do the same from sinatra_app.rb:
get '/json' do
#all_metrics = open #graphite_all_metrics
erb :json
end
or
get '/json' do
#all_metrics = Net::HTTP.get_response(URI #graphite_all_metrics)
erb :json
end
returns me a 502 bad gateway error.
Any help?
How i get #graphite_all_metrics:
#graphite_base = "http://foo-bar.com:8085/"
#graphite_all_metrics = [#graphite_base, "/metrics/index.json"].join
Your join
#graphite_all_metrics = [#graphite_base, "/metrics/index.json"].join
is adding a double slash to the URL. Use
#graphite_all_metrics = File.join(#graphite_base, "/metrics/index.json")
or just remove one of the slashes from your example.
Most browsers/programs will fix double slash errors, but there could be some issue with your server setup.
Solved. It was a misconfigured multi-domain dns. Nothing with ruby.
I am using Prawn to generate a PDF from my controller, and when accessed directly at the url, it works flawlessly, I.E. localhost:3000/responses/1.pdf
However, when I try to generate this file on the fly for inclusion in a Mailer, everything freezes up and it times out.
I have tried various methods for generating / attaching the file and none have changed the outcome.
I also tried modifying the timeout for Net::HTTP to no avail, it just takes LONGER to time out.
If I run this command on the Rails Console, I receive a PDF data stream.
Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000)
But if I include this code in my controller, it times out.
I have tried two different methods, and both fail repeatedly.
Method 1
Controller:
http = Net::HTTP.new('localhost', 3000)
http.read_timeout = 6000
file = http.get(response_path(#response, :format => 'pdf')) #timeout here
ResponseMailer.confirmComplete(#response,file).deliver #deliver the mail!
Method 1 Mailer:
def confirmComplete(response,file)
email_address = response.supervisor_id
attachments["test.pdf"] = {:mime_type => "application/pdf", :content=> file}
mail to: email_address, subject: 'Thank you for your feedback!'
end
The above code times out.
Method 2 Controller:
ResponseMailer.confirmComplete(#response).deliver #deliver the mail!
Method 2 Mailer:
def confirmComplete(response)
email_address = response.supervisor_id
attachment "application/pdf" do |a|
a.body = Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000) #timeout here
a.filename = "test.pdf"
end
mail to: email_address, subject: 'Thank you for your feedback!'
end
If I switch the a.body and a.filename, it errors out first with
undefined method `filename=' for #<Mail::Part:0x007ff620e05678>
Every example I find has a different syntax or suggestion but none fix the problem that Net::HTTP times out. Rails 3.1, Ruby 1.9.2
The problem is that, in development, you're only running one server process, which is busy generating the email. That process is sending another request (to itself) to generate a PDF and waiting for a response. The request for the PDF is basically standing in line at the server so that it can get it's PDF, but the server is busy generating the email and waiting to get the PDF before it can finish. And thus, you're waiting forever.
What you need to do is start up a second server process...
script/rails server -p 3001
and then get your PDF with something like ...
args = ['127.0.0.1','/responses/1.pdf']
args << 3001 unless Rails.env == 'production'
file = Net::HTTP.get(*args)
As an aside, depending on what server you're running on your production machine, you might run into issues with pointing at 127.0.0.1. You might need to make that dynamic and point to the full domain when in production, but that should be easy.
I agree with https://stackoverflow.com/users/811172/jon-garvin's analysis that you're only running one server process, but I would mention another solution. Refactor your PDF generation so you don't depend on your controller.
If you're using Prawnto, I'm guessing you have a view like
# app/views/response.pdf.prawn
pdf.text "Hello world"
Move this to your Response model: (or somewhere else more appropriate, like a presenter)
# app/models/response.rb
require 'tmpdir'
class Response < ActiveRecord::Base
def pdf_path
return #pdf_path if #pdf_generated == true
#pdf_path = File.join(Dir.tmpdir, rand(1e11).to_s)
Prawn::Document.generate(#pdf_path) do |pdf|
pdf.text "Hello world"
end
#pdf_generated = true
#pdf_path
end
def pdf_cleanup
if #pdf_generated and File.exist?(#pdf_path.to_s)
File.unlink #pdf_path
end
end
end
Then in your ResponsesController you can do:
# app/controllers/responses_controller.rb
def show
#response = Response.find params[:id]
respond_to do |format|
# this sends the PDF to the browser (doesn't email it)
format.pdf { send_file #response.pdf_path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'test.pdf' }
end
end
And in your mailer you can do:
# this sends an email with the PDF attached
def confirm_complete(response)
email_address = response.supervisor_id
attachments['test.pdf'] = {:mime_type => "application/pdf", :content => File.read(response.pdf_path, :binmode => true) }
mail to: email_address, subject: 'Thank you for your feedback!'
end
Since you created it in the tmpdir, it will be automatically deleted when your server restarts. You can also call the cleanup function.
One final note: you might want to use a different model name like SupervisorReport or something - Response might get you in namespacing trouble later)
I have implemented AJAX based upload in my rails project.
This is my example code. (I followed the tutorial from here.. https://github.com/valums/file-uploader)
********** Javascript Code **********
function createUploader(){
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader'),
action: '/product/upload',
});
}
window.onload = createUploader;
********** Server side **********
def upload
#filename = params['qqfile']
f = File.open('home/files/' + #filename, "wb")
str = request.body.read
f.write(str)
f.close
render :text => '{success:true}'
end
When i run my code i got the following error message in the line "str = request.body.read"
NoMethodError (undefined method `body' for #<ActionController::CgiRequest:0xb6cd71a0>):
error details More: http://www.heypasteit.com/clip/01NE
My configuration:
[mrblack# home]# ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-linux]
[mrblack# home]# rails -v
Rails 1.2.1
[mrblack# home]# gem -v
1.8.6
Can you please clear me, what did i wrong?
Becasue in Rails 1.2.1 neither ActionController::CgiRequest nor its parent ActionController::AbstractRequest contains 'body' method. You can see it if you look at these pages: cgi_process.rb and request.rb. Why do you use such old rails version??
UPDATE
#Mr. Black. You wrote "Can you please tell me any alternate way to read the incoming request similar to this request object".
You're using 'file-uploader' library from github. As I can see, that library can upload files to server side by two ways. If user has old FF, Chrome browsers or any IE version that library make a post request to iframe. If user has modern FF or Chrome version library prepares async post xmlHttpRequest. Therefore, in our rails controller we have to handle both situation. For example, for simplicity we want to write sended file data to some hard-coded place on disk.
******** app/controllers/greetings_controller.rb ********
class GreetingsController < ApplicationController
def upload
begin
is_xhr = params[:qqfile].is_a? String
data = is_xhr ? request.body : params[:qqfile]
File.open("/some_place_on_disk/bar.txt", "w") { |f| f.write(data.read) }
#result = {success: true}
if is_xhr
render :json => #result
end
# else render view
rescue Exception => e
logger.info e
#result = {error: "Error has been encountered during the processing"}
end
end
end
******** app/views/upload.html.erb ********
<%= #result.to_json %>
******** config/routes.rb ********
.....
match '/upload' => 'greetings#upload', :via => :post
.....
You can use demo.htm from github project, but you have to place it into public folder. Don't forget about fileuploader.css and fileuploader.js! :) You must change 'action' in createUploader function to action path, in my case that would be '/upload'