respond_with is asking for location on error - ruby-on-rails-3

I have a pretty standard authenticate method
private
def authenticate_user
#current_user = User.find_by_authentication_token(params[:token])
unless #current_user
error = { :error => "Invalid token." }
respond_with(error, :status => 401 )
end
end
I am calling the API to ensure the authenticate fails.
I get an error stating
ArgumentError (Nil location provided. Can't build URI.):
app/controllers/api/v1/base_controller.rb:13:in `authenticate_user'
What am I doing wrong?

By the specific flavor of your error, I am guessing that "authenticate_user" is called as part of a "create" action.
If that is the case, I believe the answer I provided here will help you as well.
Assuming, however, that this is part of creating an authenticated session, meaning there is no actual location for the newly created "resource", I would supply nil for the response location, as in:
...
respond_with(error, :status => 401, :location => nil)
...
That will make more sense once you have a look at the linked answer. If it still doesn't make sense, I'll be happy to clarify.

I changed respond_with to render and it worked:
render json: { success: false, message: "an error" }, status: 500

Related

Getting controller name from a request.referer in Rails

I know I can use request.referrer to get the full referrer URL in Rails, but is there a way to just get the controller name from the URL?
I want to see if the URL of http://myurl.com/profiles/2 includes "profiles"
I know I can use a regex to do it but I wondered if there was a better way.
Keep in mind that request.referrer gives you the url of the request before the current one. That said, here is how you can convert request.referrer to controller/actionn information:
Rails.application.routes.recognize_path(request.referrer)
it should give you something like
{:subdomain => "", :controller => "x", :action => "y"}
Here is my try which works with Rails 3 & 4. This code extracts one parameter on logout and redirects user to customized login page otherwise it redirects to general login page.
You can easily extract :controller this way. Controller part:
def logout
auth_logout_user
path = login_path
begin
refroute = Rails.application.routes.recognize_path(request.referer)
path = subscriber_path(refroute[:sub_id]) if refroute && refroute[:sub_id]
rescue ActionController::RoutingError
#ignore
end
redirect_to path
end
And tests are important as well:
test "logout to subscriber entry page" do
session[:uid] = users(:user1).id
#request.env['HTTP_REFERER'] = "http://host/s/client1/p/xyzabc"
get :logout
assert_redirected_to subscriber_path('client1')
end
test "logout other referer" do
session[:uid] = users(:user1).id
#request.env['HTTP_REFERER'] = "http://anyhost/path/other"
get :logout
assert_redirected_to login_path
end
test "logout with bad referer" do
session[:uid] = users(:user1).id
#request.env['HTTP_REFERER'] = "badhost/path/other"
get :logout
assert_redirected_to login_path
end
Inside the controller, you have the method controller_name which returns you only the name. In your case, it would return "profiles".
You may also use params[:controller] which returns the same string.

rspec let method + loop

i am having trouble running my rspec examples in a loop.
describe "GET all providers" do
let(:current_user) { Factory(:user) }
[:twitter, :facebook, :google_oauth2].each do |provider|
before :each do
current_user.confirm!
sign_in current_user
request.env['devise.mapping'] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.add_mock provider, {
:uid => '123456789',
:info => {
:email => current_user.email
}
}
end
it 'should add the authorization' do
get provider # method to create the authorization
authorization = Authorization.where(:provider => request.env["omniauth.auth"][:provider], :uid => request.env["omniauth.auth"][:uid]).first
current_user.authorizations.should include authorization
end
end
end
currently these examples all pass. the problem though is that current_user is a new user instance through each iteration of the loop, despite memoizing the current_user method. so if i add a test for current_user.authorizations.count.should == 3 it fails.
this became less of needing to actually test it, and more understanding why it isnt behaving how i expect. shouldn't let(:current_user) { Factory(:user) } persist the same user instance across all examples?
Here is a gist I came up with that might help you understand let and let!:
https://gist.github.com/3489451
let memoizes the return value within each it example, but executes the block every time it is called for the first time in the example.
For example, if you call current_user the first time in an it example block, the { Factory(:user) } block is executed. Calling current_user a second or any subsequent time within the same it example block does not execute the { Factory(:user) } block; the return value is memoized.

Rendering and re-raising exceptions in Rails controllers

I'm creating an API in Rails and I've run into a situation where I'd like to alert the user that something bad happened by passing them some JSON with an error message. However, I'd also like to re-raise the exception so that Airbrake (formerly Hoptoad) will still catch the error and notify us so that we can look into the problem a bit more.
I'm currently catching the error like so:
begin
if #myobject.update_attributes(:foo => "bar")
render :json => #myobject, :status => :ok
else
render :json => #myobject.errors, :status => :unprocessable_entity
end
rescue Exception => e
render :json => { :errors => { :message => "Uh oh! Something went wrong." } }
raise e
end
The problem is that my client never gets the JSON message since the raise e stops it from rendering and sends it a generic 500 error.
How should I fix this?
[My Solution]
As suggested by Jordan below, I simply call notify_airbrake(ex) in my code any time that I catch the exception. However, I abstracted it slightly by adding the following to my ApplicationController so that I can easily change from Airbrake to something else in the future:
class ApplicationController < ActionController::Base
...
def notify_exception_service(ex)
notify_airbrake(ex)
end
...
end
So, instead of notify_airbrake(ex) I just call notify_exception_service(ex).
From the Airbrake gem documentation:
If you want to log arbitrary things which you've rescued yourself from a controller, you can do something like this:
rescue => ex
notify_airbrake(ex)
flash[:failure] = 'Encryptions could not be rerouted, try again.'
end
The #notify_airbrake call will send the notice over to Airbrake for later analysis. While in your controllers you use the notify_airbrake method, anywhere else in your code, use Airbrake.notify.
You don't have to re-raise the exception in order to log it with in Airbrake.
As I've said on chat, I think you can't becouse of how rails render things.
When you call render, a #_something_render_variable is set, but the page is not directly render, there is still additional call. Raising an exception obviusly block this flow, actually breaking the render of the webpage.
Changing this behaviour is really hard, you must alias the render method and work on it, I had a similar problem.

Debug the create! method inside the controller create method

The rails 3 appis is using the create! method inside the create of a controller.
Sometimes it works, and sometimes it does not.It fails consistently with always the same use case, however i have checked and rechecked and cannot understand why it fails.
The create! method fails silently, there is no indication on the logs of the problem. How can I make the create! methode more verbose?
Code :
class NotificationPaiementsController < ApplicationController
protect_from_forgery :except =>[:create]
skip_before_filter :authorize, :only => [:create]
def create
logger.debug "params is #{params}"
logger.debug "invoice is #{params[:invoice]}"
logger.debug "payment_status is #{params[:payment_status]}"
logger.debug "txn_id is #{params[:txn_id]}"
#notification_paiement = NotificationPaiement.create!(:params => params,
:cart_id => params[:invoice],
:status=> params[:payment_status],
:transaction_id => params[:txn_id])
logger.debug "notification_paiement is #{#notification_paiement}"
render :nothing=>true
end
end
EDIT:
Thx for your answers, it would have been faster to catch exception, but i managed to identify the problem using new and savevia the console. At the save i had an error about UTF-8 encoding : ArgumentError: invalid byte sequence in UTF-8.
Paypal was changing "molière" in "moli\xE8re" and the error was never displayed.
The create! constructor raises an exception if it fails:
Creates an object just like Base.create but calls save! instead of save so an exception is raised if the record is invalid.
So, if you're going to use create!, you should wrap it in exception handling:
begin
#notification_paiement = NotificationPaiement.create!(...
rescue ActiveRecord::RecordInvalid => e
# Deal with your errors.
end
You can temporarily remove the backtrace silencers in config/initializers/backtrace_silencers.rb in case exception info is being swallowed.

Rails 3 assertions failure message: "Expected block to return true value" not helpful; what gives?

This occurs frequently in my controller and route tests. Example, given the route
match "/about", :to => "about#profile"
And the test
test "/about goes to about/profile" do
assert_generates "/about/", { :controller => "about", :action => "profile" }
end
The only failure message is "Expected block to return true value". This happens also with tests like:
test "bills should redirect to /bills" do
get :bills
assert_redirected_to user_bills_path(#user)
end
If my controller doesn't' redirect to user_bills_path(#user), I get the same error: "Expected block to return true value"
This is very annoying for test-driving, as I cannot easily check that my assertion is failing before writing production code or failing because I've written the incorrect test.
It seems to be coming from Rails testing stuff. Any way to avoid this or get better messages?