In a rails app I am running:
54 def itunes_all_apps
55 begin
56 Spaceship::Tunes.login(params[:itunes_username], params[:itunes_password])
57 apps = Spaceship::Tunes::Application.all
58 render json: apps.to_json, status: 200
59 rescue => e
60 render json: {error: e}.to_json, status: 500
61 end
62 end
It returns a status 500 error with no other information every time.
However, if I change this around slightly, for example getting teams (note, from Spaceship, not Spaceship::Tunes) this works fine:
def itunes_all_apps
begin
spaceship = Spaceship.login(params[:itunes_username], params[:itunes_password])
teams = spaceship.teams
render json: teams.to_json, status: 200
rescue => e
render json: {error: e}.to_json, status: 500
end
end
I'm not using any fast file or or config or anything. Just passing in a username and password via an api call and trying to get a response back. I'm new to rails so it may be my implementation of the Spaceship examples provided.
Using spaceship 0.36.1 gem (the latest)
I've pored through the docs to no avail. Grasping for any leads on what I'm doing wrong.
http://www.rubydoc.info/gems/spaceship/Spaceship/Tunes
https://github.com/fastlane/fastlane/blob/master/spaceship/docs/iTunesConnect.md
Someone suggested I run these two commands in irb, which I did, and they worked perfect!
Spaceship::Tunes.login('myAppleId', 'myPassword')
Spaceship::Tunes::Application.all
So it's not an iTunes account problem or credentials problem (because it works in irb), routes problem (because I ran both rails methods above with same route), or params problem (because I ran both rails methods above with same param names).
I really appreciate any suggestions. Thanks.
Edit:
Commenting out begin, rescue, and rending the error, the stack trace is as follows:
2016-10-24T17:47:34.974650+00:00 app[web.1]: Started POST "/api/v1/users/13/itunes_all_apps" for 162.237.102.13 at 2016-10-24 17:47:34 +0000
2016-10-24T17:47:34.977478+00:00 app[web.1]: Processing by Api::V1::UsersController#itunes_all_apps as JSON
2016-10-24T17:47:34.977521+00:00 app[web.1]: Parameters: {"itunes_username"=>"myCorrectUsername", "itunes_password"=>"[FILTERED]", "team_id"=>"myCorrectTeamId", "id"=>"13", "user"=>{}}
2016-10-24T17:47:35.629629+00:00 heroku[router]: at=info method=POST path="/api/v1/users/13/itunes_all_apps" host=myHerokuApp.herokuapp.com request_id=002d906d-354e-4633-8b54-71aa5181e3a7 fwd="161.237.102.13" dyno=web.1 connect=2ms service=657ms status=500 bytes=259
2016-10-24T17:47:35.619597+00:00 app[web.1]: Completed 500 Internal Server Error in 642ms (ActiveRecord: 0.0ms)
2016-10-24T17:47:35.620430+00:00 app[web.1]:
2016-10-24T17:47:35.620432+00:00 app[web.1]: IOError (not opened for reading):
2016-10-24T17:47:35.620434+00:00 app[web.1]:
2016-10-24T17:47:35.620433+00:00 app[web.1]: app/controllers/api/v1/users_controller.rb:58:in `itunes_all_apps'
It seems that Spaceship::Fastlane::Application does not implement as_json method and the default as_json touches some IO object, which cannot be represented as json.
My suggestion would be to create JSON serializer. You could use active_model-serializer, but if you do not want to create a dependency just for one object, then you can create your own serializer.
class SpaceshipApplicationSerializer
attr_reader :spaceship_applications
def initialize(spaceship_applications)
#spaceship_applications = spaceship_applications
end
def as_json(options = {})
spaceship_applications.each_with_object([]) do |spaceship_application, memo|
memo << object_as_json(spaceship_application)
end
end
def object_as_json(object)
attributes.each_with_object({}) do |attribute, memo|
memo[attribute] = object.send(attribute)
end
end
def attributes
[
:apple_id,
:name,
:vendor_id,
:bundle_id,
:last_modified,
:issues_count,
:app_icon_preview_url
]
end
end
# In your controller
def itunes_all_apps
begin
Spaceship::Tunes.login(params[:itunes_username], params[:itunes_password])
apps = Spaceship::Tunes::Application.all
render json: SpaceshipApplicationSerializer.new(apps).to_json, status: 200
rescue => e
render json: {error: e}.to_json, status: 500
end
end
EDIT:
Yes, the classes return an array, but the actual objects in array don't play nicely with json. It's hard to say if the problem is with the library - on one hand Spaceship::Tunes::Application not returning a proper json representation is a missing feature, but if the to_json raises an exception (a method the class responds to) - then I would say that is a bug.
Creating your own serializer to build json representation the way you want it - is a common pattern.
Related
I just deployed my first app to heroku and it used a Rails API (backend) and a React frontend. When I deployed my app I get 401 unauthorized errors whenever I try to make a request that involves the use of a JSON Web Token(JWT). I am sending the token from localstorage in my app and everything worked fine when I was sending it in my development environment. I only have this issue in production.
When I make the fetch request from my frontend and send over my JWT to my backend, I get the following messages in my heroku server logs:
2020-11-29T04:45:31.742735+00:00 app[web.1]: I, [2020-11-29T04:45:31.742670 #4] INFO -- : [f3c19eae-e431-4c9f-b93b-7499797f2c03] [active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.13ms)
2020-11-29T04:45:31.742984+00:00 app[web.1]: I, [2020-11-29T04:45:31.742919 #4] INFO -- : [f3c19eae-e431-4c9f-b93b-7499797f2c03] Filter chain halted as :authorized rendered or redirected
2020-11-29T04:45:31.744091+00:00 app[web.1]: I, [2020-11-29T04:45:31.744019 #4] INFO -- : [f3c19eae-e431-4c9f-b93b-7499797f2c03] Completed 401 Unauthorized in 2ms (Views: 0.7ms | Allocations: 218)
Another strange thing about this is that I get an error message along with the 401 status error in my React frontend that tells me to Please Log in even though I logged into my app to receive a token from my backend before I even attempted to make another fetch request
Below I will post other relevant code snippets so that you can see what I was trying to do
Here is the Code in my frontend that sends the request
addToCart = () =>{
//make a fetch request to add the item in the customer's current cart
fetch("https://health-and-fit-store-api.herokuapp.com/cart_products",{
method:"POST",
headers:{
"Authorization": localStorage.token,
"Content-Type":"application/json",
Accept:"application/json"
},
body:JSON.stringify({
productId :this.props.id
})
})
.then(res => res.json())
.then(data => {
this.props.addToCart(data)
toast.dark(`Added ${data.product.name.toLowerCase()} to your cart`)
})
}
Here is the code in my Rails API that receives the request
before_action :authorized, only: [:create,:delete]
def create
#will be receiving token in fetch request
#use the of the current cart and the product id passed in by the post request
current_cart = #customer.carts.find_by(checked_out:false)
product = Product.find(params[:productId])
new_cart_product = CartProduct.create(cart:current_cart,product:product, quantity:1)
render json: new_cart_product
end
Here is the code from my application controller that I used to set up JWT
class ApplicationController < ActionController::API
def encode_token(payload)
# should store secret in env variable
JWT.encode(payload, ENV['jwt_encode_string'])
#byebug
end
def auth_header
# { Authorization: 'Bearer <token>' }
request.headers['Authorization']
end
def decoded_token
if auth_header
token = auth_header
# header: { 'Authorization': '<token>' }
begin
JWT.decode(token, ENV['jwt_encode_string'], true, algorithm: 'HS256')
rescue JWT::DecodeError
nil
end
end
end
def logged_in_customer
if decoded_token
customer_id = decoded_token[0]['customer_id']
#customer = Customer.find_by(id: customer_id)
end
end
def logged_in?
!!logged_in_customer
end
def authorized
render json: { error_message: 'Please log in' }, status: :unauthorized unless logged_in?
end
end
If anyone can help me out with this, I would really appreciate it, I've been stuck on this for days. Also please note that I have checked out every other post involving this issue on StackOverflow and have exhausted every kind of search on Google that I could think of.
thanks to #snake, I actually ended up solving this issue. The problem wasn't with the token I was using, but their suggestion led me to go back and check out my fetch requests to the api endpoint and I had an extra comma at the end of the request that was causing the 401 status code error.
Once I fixed that, everything worked beautifully.
Within an engine w/ an API, when querying the API an exception is thrown, but the server response is not using the response specified, and instead rendering a default debug response (in production).
I can confirm that the exception is caught by the controller:
Started GET "/api_v2/admin/submissions?system_id=123&spt_id=123" for
127.0.0.1 at 2019-03-15 10:04:37 -0400
Processing by ApiV2::Admin::SubmissionsController#show as JSON
Parameters: {"system_id"=>"123", "spt_id"=>"123"}
[3, 12] in /....../emp_api_v2/app/controllers/emp_api_v2/application_controller.rb
3:
4: before_action :doorkeeper_authorize!
5:
6: rescue_from ::ActiveRecord::RecordNotFound do |e|
7: byebug
=> 8: response(:standard_error, 500, "Hello World")
9: end
10:
11: def doorkeeper_unauthorized_render_options(error: nil)
12: { json: { message: "Not authorized" }, status: 403 }
(byebug) cont
Completed 500 Internal Server Error in 5220ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound - Couldn't find Emp::System with 'id'=123:
The server is expected to respond with 500 Server Error not the debug error stacktrace.
Why are there two responses, even though the controller catches the exception and runs a response method.
NOTE: This happens in dev and prod ! Server responds with 500 first (my catch response) but then with a stacktrace and 404 (As this is the source of the error and correct exception). It breaks my tests as the past response was 500. I was not able to revert my server to the old behavior by: reinstalling ruby, reinstalling rails + all gems + rolling back all changes throughout the repo. This behavior seems to be externally set by a ENV variable or something else.
I'd be grateful for any insight.
Edit: The (api) app controller looks like this:
module ApiV2
class ApplicationController < ActionController::API
before_action :doorkeeper_authorize!
rescue_from ::ActiveRecord::RecordNotFound do |e|
response(:standard_error, 500, "Hello World")
end
def doorkeeper_unauthorized_render_options(error: nil)
{ json: { message: "Not authorized" }, status: 403 }
end
end
end
Edit 2: I was able to get the correct response by wrapping the call in a rescue block. That code will result in a lot of begin/rescue blocks though as each of them has a specific error message.
begin
system = Emp::System.find(sys_id)
rescue
render json: { status: 500, content: "Specific Error msg" } and return
end
Originally i had a method as follows:
def handle_exception(message, &block)
begin
block.call
rescue Exception => e
render json: { message: message }, status: 500 and return
end
end
This will result in double render error as it's not returning from the top-level method but from the block.
I'm new to Ruby, please bear with me if this is a stupid question, or if I'm not following the best practice.
I'm finding an object in the DB using find(), and expect it to throw RecordNotFound in case the object of the id does not exist, like this.
begin
event = Event.find(event_id)
rescue ActiveRecord::RecordNotFound => e
Rails.logger.debug "Event does not exist, id: " + event_id
return {
# return "unauthorized" to avoid testing existence of event id
# (some redacted codes)
}
end
But somehow it is not caught (the log in the rescue block is not printed) and the entire program just return internal server error. Here's the stack trace:
Completed 500 Internal Server Error in 22ms (ActiveRecord: 1.0ms)
ActiveRecord::RecordNotFound (Couldn't find Event with 'id'=999):
lib/sync/create_update_event_handler.rb:78:in `handleRequest'
app/controllers/sync_controller.rb:36:in `block in sync'
app/controllers/sync_controller.rb:31:in `each'
app/controllers/sync_controller.rb:31:in `sync'
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (6.4ms)
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.3ms)
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.9ms)
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (36.6ms)
The only thing I can think of is there are two different ActiveRecord::RecordNotFound, and I'm catching the wrong one, but I don't know if it is the case or how I can verify it.
What did I do wrong?
======================================
Update
The problem is in the rescue block, I was concatenating event_id (an integer) to a string.
The RecordNotFound exception was indeed caught, but when the type error was thrown in the rescue block, the wrong error message was printed.
You won't get an error if you do
event = Event.find_by(id: event_id)
In this case if the record can't be found by ID it will just event == nil be nil.
In this case if the record can't be found by ID it will just event == nil be nil.
The code you pasted works fine for me. If you don't see output in the log, check your environment and log level settings INFO, WARN, DEBUG etc. 500 error indicates some kind of controller action raising the error.
see Set logging levels in Ruby on Rails
To be sure your rescue block is executing try doing something besides log. If you're running a development server you can try :
begin
event = Event.find(event_id)
rescue ActiveRecord::RecordNotFound => e
msg = "Event does not exist, id: #{event_id.to_s}"
Rails.logger.debug msg.
puts msg
binding.pry # if you have gem 'pry' in your development gems.
File.open('test.log', 'w') {|f| f.write msg} #check if this appears in root of your app
return {
# return "unauthorized" to avoid testing existence of event id
# (some redacted codes)
}
end
UPDATE: I changed the string interpolation according to your answer. You can also call .to_s inside interpolation instead of closing quotes and appending.
Turned out the error message is wrong.
The problem is that I was concentating the event_id (an integer) to a string.
But somehow Rails prints out the RecordNotFound exception.
The problem is fixed by replacing
Rails.logger.debug "Event does not exist, id: " + event_id
with
Rails.logger.debug "Event does not exist, id: " + event_id.to_s
Thanks #lacostenycoder for bringing my attention to the error message.
#event = Event.find(params[:id]). you should write instead params[:id] .That's the cause of an error.
im trying to get AMF to work with Rails3.
I have succesfully installed rails3-amf-0.1.0 gem and the RocketAMF-0.2.1 gem.
In my app there is a controller with the following code:
def getRandomCards
#incoming = params[0]
#cards = Cardvo.first
respond_with(#cards) do |format|
format.amf { render :amf => #cards.to_amf}
end
end
through a call from Actionscript i would like to return some data in amf format.
further more, as mentioned in the instructions for rails3-amf i did the following.
in my production.rb under config/environment i added the line
config.rails3amf.map_params :controller => 'CardvosController', :action => 'getRandomCards'
an my amf gateway got
config.rails3amf.gateway_path = "/gateway"
The problem is:
Any call from Actionscript / Flash raises the following
(taken from the log )
Started POST "/gateway" for 192.178.168.1 at Fri Nov 19 15:13:28 +0100 2010
Processing by CardvosController#getRandomCards as AMF
Parameters: {0=>100.0}
[1m[36mSQL (0.4ms)[0m [1mSHOW TABLES[0m
[1m[35mCardvo Load (0.2ms)[0m SELECT `cardvos`.* FROM `cardvos` LIMIT 1
Completed 200 OK in 13ms (Views: 0.9ms | ActiveRecord: 0.5ms)
NoMethodError (undefined method `constructed?' for #<RocketAMF::Envelope:0x39ba868>):
The Amf file is created but the method, which is in remoting.rb from RocketAMF could not be found.
I think the error is thrown at request_parser.rb from Rails3AMF asking for constructed?
# Wrap request and response
env['rack.input'].rewind
env['rails3amf.request'] = RocketAMF::Envelope.new.populate_from_stream(env['rack.input'].read)
env['rails3amf.response'] = RocketAMF::Envelope.new
# Pass up the chain to the request processor, or whatever is layered in between
result = #app.call(env)
# Calculate length and return response
if env['rails3amf.response'].constructed?
For me it seems it is looking at the wron class for the method.
Where
NoMethodError (undefined method `constructed?' for #RocketAMF::Envelope:0x39ba868):
the essential part is
RocketAMF::Envelope:0x39ba868
which should be
RocketAMF:ANOTHER_CLASS:Envelope:0x39ba868
Am i right and where the heck is the error ?
Any help would be appreciated!
chris
I have a form_tag that works fine using html, but when I use ajax with the remote => true I am getting this error:-
My terminal log shows:-
Started GET "/" for 127.0.0.1 at 2010-11-01 01:19:49 +0000
Processing by HomepagesController#index as HTML
Homepage Load (0.6ms) SELECT "homepages".* FROM "homepages"
Rendered homepages/index.html.erb within layouts/application (23.0ms)
Completed 200 OK in 40ms (Views: 27.3ms | ActiveRecord: 0.6ms)
Error during failsafe response: incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string)
* then a load of cleaner.rb stuff
then:-
Started GET "/homepages?utf8=%E2%9C%93&search=hom" for 127.0.0.1 at 2010-11-01 01:19:56 +0000
Processing by HomepagesController#index as JS
Parameters: {"utf8"=>"✓", "search"=>"hom"}
Homepage Load (0.5ms) SELECT "homepages".* FROM "homepages" WHERE (section LIKE '%hom%')
Rendered homepages/index.js.erb (2.9ms)
Completed in 19ms
In my index.js.erb I have:-
$("testsearch").update("<%= escape_javascript(render(#homepages))%>");
and in my Controller I have:-
def index
#homepages = Homepage.search(params[:search])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #homepages }
format.js { render :layout => false }
end
in my view I have:-
which prints #homepages using a table using <% #homepages.each do |homepage| %> which is not being updated.
Anyone have any ideas as to why I get this error.
I have cracked it by going onto an IRC chat room (irc.freenode.net RubyonRails) and a ProjectZen (human being somewhere out there in the ether) helped me to get it working.
Apparently what was happening was that I was following Ryan Bates who does many extremely good Railcast videos, but he builds on previous Railcast. Therefore in his 205 Railscast, which deals with Ajax calls, he did not mention that you must have:-
format.js in the action in the controller.
His xxxx.searchxxxxx needs to be created in the controller or model.
And that when I did :-
<%= render(#homepages)%> <!-- (in his case <%= render(#products)%>) -->
The render was looking for a partial called "_homepage" (not "homepages") (I did not even have a partial therefore I got the UTF8 to ASCII error).
And then in "_homepage" I would add my code to render the results.
What I have now done in my index.html.erb is to put <%= render(#homepages)%>, in the (div id = testsearch) in place of the code I use to render #homepages and then place that code in a partial "_homepage". Now I can use "_homepage" for the html and the Ajax call.
At the moment I have a slight problem in that it is rendering all the data in the"#homepages" as many times as the number of records. At the moment I do not know why, but at least the Ajax call is working.