Mongoid dynamic finder with Mongoid::Errors::DocumentNotFound exception raised - ruby-on-rails-3

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

Related

Defining my Custom devise authentication strategy throws 'load_missing_constant' error

In my app, I am trying to define a custom strategy but it throws some errors... Here's what I am doing:
# myrailsapp/lib/devise/strategies
require 'devise/strategies/database_authenticatable'
module Devise
module Strategies
class CustomAuth < Devise::Strategies::DatabaseAuthenticatable
def valid?
Rails.logger.info("\n\nIn CustomAuth.valid\n\n")
true
end
def authenticate!
Rails.logger.info("\n\nCalled My Authenticate!\n\n")
super
end
end
end
end
Warden::Strategies.add(:custom_auth, Devise::Strategies::CustomAuth)
# config/initializer.rb
config.warden do |manager|
# manager.strategies.add(:custom_auth, Devise::Strategies::CustomAuth)
manager.default_strategies(:scope => :user).unshift :custom_auth
end
When I try to run this, I get this error:
/usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:490:in load_missing_constant': Expected app/helpers/custom_auth.rb to define CustomAuth (LoadError)
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:181:inconst_missing'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:179:in each'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:179:inconst_missing'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:501:in load_missing_constant'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:181:inconst_missing'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:179:in each'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:179:inconst_missing'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:501:in load_missing_constant'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:181:inconst_missing'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:179:in each'
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:179:inconst_missing'
from /home/rjain/src/qbol/tapp/config/initializers/devise.rb:212
Now, when I move the same file to my app/helpers directory, I get the same error, but if I remove the module Devise and module Strategies, things start to work. Two questions:
How to ensure that I can create the file in my lib/devise/strategies folder?
How to make it work so that I can use it within Devise::Strategies module as I described above?

Getting ActiveModel::Callbacks to work with ActiveResource

I am trying to get ActiveModel::Callbacks to work with ActiveResource (specifically after_initialize) for a Rails 3 app, but I can't seem to get it to work. I don't get any errors, but the callback method is never executed.
Here is a snippet of code
class User < ActiveResource::Base
extend ActiveModel::Callbacks
define_model_callbacks :initialize, :only => :after
after_initialize :update_info
def update_info
puts 'info'
end
end
For some reason, the update_info is never executed. Anyone have any idea how to get this to work?
In case anyone is interested, I re-read the documentation on this, and what I thought was an explanation of how the code worked under the covers, turned out to be a requirement which stated that I needed to override the method I was adding callbacks to:
def initialize(attributes = {}, persisted = false)
run_callbacks :initialize do
super(attributes, persisted)
end
end
This seems incredibly counter-intuitive to me, as it expects you to track down the signature of the existing method, overwrite it, and add the callback functionality. I hope I am missing something here, and simply making a mistake, but I haven't gotten any other solution to work.
Anyways, here is a monkey patch to provide this callback to all AR classes:
module ActiveResource
class Base
extend ActiveModel::Callbacks
define_model_callbacks :initialize, :only => :after
def initialize_with_callback(attributes = {}, persisted = false)
run_callbacks :initialize do
initialize_without_callback(attributes, persisted)
end
end
alias_method_chain :initialize, :callback
end
end

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.

Error when saving a Backbone.js model with Rails

I have Backbone.js collection and model for a project object:
window.Project = Backbone.Model.extend();
window.Projects = Backbone.Collection.extend({
model: Project,
url: '/projects'
});
I have setup a rails controller to respond to the Backbone.js collection:
class ProjectsController < ApplicationController
def index
render :json => Project.all
end
def create
project = Project.create! params
render :json => project
end
end
Index works fine and I get a list of projects in my web app. The problem is if I try and create a model on the Projects collection I get a 500 error from the server.
The error message on the server is as follows:
Started POST "/projects" for 127.0.0.1 at 2011-08-21 08:27:56 +0100
Processing by ProjectsController#create as JSON
Parameters: {"title"=>"another test"}
Completed 500 Internal Server Error in 16ms
ActiveRecord::UnknownAttributeError (unknown attribute: action):
app/controllers/projects_controller.rb:8:in `create'
I am not sure what the unknown attribute: action is referring to.
For info I have set up the projects_controller as resources :projects. I have also set rails to ActiveRecord::Base.include_root_in_json = false.
Yes, Rails always adds the action and controller to params. The parameters come from ActionDispatch::Http::Parameters:
def parameters
#env["action_dispatch.request.parameters"] ||= begin
params = request_parameters.merge(query_parameters)
params.merge!(path_parameters)
encode_params(params).with_indifferent_access
end
end
And path_parameters:
Returns a hash with the parameters used to form the path of the request. Returned hash keys are strings:
{'action' => 'my_action', 'controller' => 'my_controller'}
So you shouldn't be doing project = Project.create! params. You could go the update_attributes route:
project = Project.new
project.update_attributes params[:model_name]
But this assumes that you have what you need in a sub-hash of params and it won't call your validators. Backbone won't namespace your attributes by default but you could override Backbone.sync and do it yourself. Still, you probably want your validations so update_attributes should generally be avoided.
Your best bet is to pull exactly the attributes out of params that you're expecting to be there. This is even the Backbone recommended practise:
*(In real code, never use update_attributes blindly, and always whitelist the attributes you allow to be changed.)*
You can enable parameter wrapping. Add a file in the initializer directory with:
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
and, for json request, you post params will now be wrapped with the model name.

How do I write a Rails 3.1 engine controller test in rspec?

I have written a Rails 3.1 engine with the namespace Posts. Hence, my controllers are found in app/controllers/posts/, my models in app/models/posts, etc. I can test the models just fine. The spec for one model looks like...
module Posts
describe Post do
describe 'Associations' do
it ...
end
... and everything works fine.
However, the specs for the controllers do not work. The Rails engine is mounted at /posts, yet the controller is Posts::PostController. Thus, the tests look for the controller route to be posts/posts.
describe "GET index" do
it "assigns all posts as #posts" do
Posts::Post.stub(:all) { [mock_post] }
get :index
assigns(:posts).should eq([mock_post])
end
end
which yields...
1) Posts::PostsController GET index assigns all posts as #posts
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"posts/posts"}
# ./spec/controllers/posts/posts_controller_spec.rb:16
I've tried all sorts of tricks in the test app's routes file... :namespace, etc, to no avail.
How do I make this work? It seems like it won't, since the engine puts the controller at /posts, yet the namespacing puts the controller at /posts/posts for the purpose of testing.
I'm assuming you're testing your engine with a dummy rails app, like the one that would be generated by enginex.
Your engine should be mounted in the dummy app:
In spec/dummy/config/routes.rb:
Dummy::Application.routes.draw do
mount Posts::Engine => '/posts-prefix'
end
My second assumption is that your engine is isolated:
In lib/posts.rb:
module Posts
class Engine < Rails::Engine
isolate_namespace Posts
end
end
I don't know if these two assumptions are really required, but that is how my own engine is structured.
The workaround is quite simple, instead of this
get :show, :id => 1
use this
get :show, {:id => 1, :use_route => :posts}
The :posts symbol should be the name of your engine and NOT the path where it is mounted.
This works because the get method parameters are passed straight to ActionDispatch::Routing::RouteSet::Generator#initialize (defined here), which in turn uses #named_route to get the correct route from Rack::Mount::RouteSet#generate (see here and here).
Plunging into the rails internals is fun, but quite time consuming, I would not do this every day ;-) .
HTH
I worked around this issue by overriding the get, post, put, and delete methods that are provided, making it so they always pass use_route as a parameter.
I used Benoit's answer as a basis for this. Thanks buddy!
module ControllerHacks
def get(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "GET")
end
# Executes a request simulating POST HTTP method and set/volley the response
def post(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "POST")
end
# Executes a request simulating PUT HTTP method and set/volley the response
def put(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "PUT")
end
# Executes a request simulating DELETE HTTP method and set/volley the response
def delete(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "DELETE")
end
private
def process_action(action, parameters = nil, session = nil, flash = nil, method = "GET")
parameters ||= {}
process(action, parameters.merge!(:use_route => :my_engine), session, flash, method)
end
end
RSpec.configure do |c|
c.include ControllerHacks, :type => :controller
end
Use the rspec-rails routes directive:
describe MyEngine::WidgetsController do
routes { MyEngine::Engine.routes }
# Specs can use the engine's routes & named URL helpers
# without any other special code.
end
– RSpec Rails 2.14 official docs.
Based on this answer I chose the following solution:
#spec/spec_helper.rb
RSpec.configure do |config|
# other code
config.before(:each) { #routes = UserManager::Engine.routes }
end
The additional benefit is, that you don't need to have the before(:each) block in every controller-spec.
Solution for a problem when you don't have or cannot use isolate_namespace:
module Posts
class Engine < Rails::Engine
end
end
In controller specs, to fix routes:
get :show, {:id => 1, :use_route => :posts_engine}
Rails adds _engine to your app routes if you don't use isolate_namespace.
I'm developing a gem for my company that provides an API for the applications we're running. We're using Rails 3.0.9 still, with latest Rspec-Rails (2.10.1). I was having a similar issue where I had defined routes like so in my Rails engine gem.
match '/companyname/api_name' => 'CompanyName/ApiName/ControllerName#apimethod'
I was getting an error like
ActionController::RoutingError:
No route matches {:controller=>"company_name/api_name/controller_name", :action=>"apimethod"}
It turns out I just needed to redefine my route in underscore case so that RSpec could match it.
match '/companyname/api_name' => 'company_name/api_name/controller_name#apimethod'
I guess Rspec controller tests use a reverse lookup based on underscore case, whereas Rails will setup and interpret the route if you define it in camelcase or underscore case.
It was already mentioned about adding routes { MyEngine::Engine.routes }, although it's possible to specify this for all controller tests:
# spec/support/test_helpers/controller_routes.rb
module TestHelpers
module ControllerRoutes
extend ActiveSupport::Concern
included do
routes { MyEngine::Engine.routes }
end
end
end
and use in rails_helper.rb:
RSpec.configure do |config|
config.include TestHelpers::ControllerRoutes, type: :controller
end