Debug the create! method inside the controller create method - ruby-on-rails-3

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.

Related

undefined method `downcase' for nil:NilClass

describe GameSystem::Client do
def client
GameSystem::Client.new(signature_method: 'HMAC-SHA1', oauth_key: 'kk', oauth_secret: 'bb', oauth_access_token_url: 'https:://localhost')
end
before :each do
WebMock.reset!
end
describe 'response' do
context 'wrong path' do
it 'raises JSON::ParserError on invalid return value' do
stub_request(:get,"https://games.com/game_id/invalid_id").to_return(:status => 200, :body => 'invalid json', :headers => {})
Rails.logger.info "#{client.games_by_id("invalid_id")}"
end
end
end
end
Can anyone let me know what i have been doing wrong or what i could do different ?.
It basically throws this error at the line
#access_token = #consumer.get_access_token(nil) in my client
It'd be good if you could be a bit more specific on what you're trying to do.
The error is pretty self explanatory. You're getting downcase for nil:NilClass because you're trying to call downcase for a nil object...Provide more information and we'll be able to help better.
I realize this question was from way back, but I just ran into this issue in a test suite. Sounded familiar.
My error was
Failure/Error: get :index
ActionView::Template::Error:
undefined method `downcase' for nil:NilClass
As it turns out, i'm using mobile-fu and I was stubbing is_mobile_device? without stubbing also mobile_device. Somewhere along the way, mobile-fu was trying to downcase the device name, which was nil. By adding a stub for the mobile_device, things cleared up. In a before block in the specs, I added:
controller.stub(:is_mobile_device? => true, :mobile_device => 'iphone')
If you're not using mobile-fu, you probably have a different issue. I was able to track the actual issue down with pry and pry-debugger. Definitely worthwhile tools to look into.

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.

respond_with is asking for location on error

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

Testing after_create hooks with rspec

I have code in my model (RoR 3.0.x) that is more or less like this:
class Message
after_create :notify
protected
def notify
if visible?
Notifier.message_from_portfolio( user, self ).deliver
else
Notifier.invisible_message_from_portfolio( user, self ).deliver
end
end
end
And I'm using the latest rspec gem to test it.
The problem is that I'm not able to test the notify method: if I test it directly I can't because it's protected, if I create a message and set expectations it doesn't work because apparently even though rspec runs the notify metod I'm not able to catch the calls in time.
My spec is:
describe :notification do
it "should send the whole message by email when visible" do
u = Factory.create( :user, :account_type => 1 )
message = u.messages.build( :body => "Whatever", :author => "Nobody", :email => "test#example.com" )
Notifier.should_receive( :message_from_portfolio )
message.save
end
end
The object Notifier never receives message_from_portfolio. What am I doing wrong? Suggestions?
Factory.create has already saved message, so it is not being created, just saved. Substitute it with Factory.build and all should be fine.
Are you sure the callback is being reached? after_create doesn't get executed if the instance is invalid.
You could set an expectation for debugging purposes:
message.should_receive(:after_create)
Or maybe visible? returns false? To check for that you could use a negative expectation:
Notifier.should_not_receive(:invisible_message_from_portfolio)

Mongoid dynamic finder with Mongoid::Errors::DocumentNotFound exception raised

I'm building a REST api for this project that uses Mongoid.
I've setup the following to catch the Mongoid::Errors::DocumentNotFound exception:
rescue_from Mongoid::Errors::DocumentNotFound in my base controller
In my controller I've this query code:
#current_account.users.find(:first, :conditions => {:name => "some_name"})
The above query just returns nil. It doesn't raise the exception.
Tried with another syntax as well:
User.find(:conditions => {:name => "same"}).first
All those methods just runs where internally and afaik where doesn't raise exception, its simply returns []
So what can be the solution to this? I want partially dynamic finder but should raise the exception too?
I've met same problem today, and found another solution.
Set raise_not_found_error to false. so your config/mongoid.yml should be
development:
host: localhost
port: 10045
username: ...
password: ...
database: ...
raise_not_found_error: false
from http://mongoid.org/docs/installation/configuration.html
I believe that Mongoid will only raise a DocumentNotFound exception when using the find method by passing in an object's id (and not with conditions). Otherwise it will return nil. From the Mongoid source:
# lib/mongoid/errors/document_not_found.rb
# Raised when querying the database for a document by a specific id which
# does not exist. If multiple ids were passed then it will display all of
# those.
You will have to check manually to see if you got any results and either raise the DocumentNotFound exception yourself (not great), or raise your own custom exception (better solution).
An example of the former would be something like this:
raise Mongoid::Errors::DocumentNotFound.new(User, params[:name]) unless #current_account.users.first(:conditions => {:name => params[:name]})
Update: I haven't tested any of this, but it should allow you to make calls like (or at least point you in the right direction - i hope!):
#current_account.users.where!(:conditions => {:name => params[:name]})
Which will throw a custom Mongoid::CollectionEmpty error, if the collection returned from the query is empty. Note that it's not the most efficient solution, since in order to find out if the returned collection is empty - it has to actually process the query.
Then all you need to do is rescue from Mongoid::CollectionEmpty instead (or as well).
# lib/mongoid_criterion_with_errors.rb
module Mongoid
module Criterion
module WithErrors
extend ActiveSupport::Concern
module ClassMethods
def where!(*args)
criteria = self.where(args)
raise Mongoid::EmptyCollection(criteria) if criteria.empty?
criteria
end
end
end
end
class EmptyCollection < StandardError
def initialize(criteria)
#class_name = criteria.class
#selector = criteria.selector
end
def to_s
"Empty collection found for #{#class_name}, using selector: #{#selector}"
end
end
end
# config/application.rb
module ApplicationName
class Application < Rails::Application
require 'mongoid_criterion_with_errors'
#...snip...
end
end
# app/models/user.rb
class User
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Criterion::WithErrors
#...snip...
end