Mongoid::Errors::DocumentNotFound raise_not_found_error - ruby-on-rails

* updated at the bottom *
When looking for user that doesnt exist, I am getting:
Mongoid::Errors::DocumentNotFound in UsersController#show
Problem:
Document(s) not found for class User with id(s) 22. Summary: When
calling User.find with an id or array of ids, each parameter must
match a document in the database or this error will be raised. The
search was for the id(s): 22 ... (1 total) and the following ids were
not found: 22. Resolution: Search for an id that is in the database or
set the Mongoid.raise_not_found_error configuration option to false,
which will cause a nil to be returned instead of raising this error
when searching for a single id, or only the matched documents when
searching for multiples.
However I am setting raise_not_found_error to false
mongoid.yml
development:
adapter: 'mongoid'
# Configure available database sessions. (required)
sessions:
# Defines the default session. (required)
default:
# Defines the name of the default database that Mongoid can connect to.
# (required).
database: blog_development
# Provides the hosts the default session can connect to. Must be an array
# of host:port pairs. (required)
hosts:
- localhost:27017
options:
allow_dynamic_fields: false
identity_map_enabled: true
include_root_in_json: true
include_type_for_serialization: true
# Note this can also be true if you want to preload everything, but this is
# almost never necessary. Most of the time set this to false.
preload_models:
- Canvas
- Browser
- Firefox
scope_overwrite_exception: true
raise_not_found_error: false
skip_version_check: false
use_activesupport_time_zone: false
use_utc: true
# Configure Mongoid specific options. (optional)
options:
# Enable the identity map, needed for eager loading. (default: false)
# identity_map_enabled: false
# Includes the root model name in json serialization. (default: false)
# include_root_in_json: false
# Include the _type field in serializaion. (default: false)
# include_type_for_serialization: false
# Preload all models in development, needed when models use
# inheritance. (default: false)
# preload_models: false
# Protect id and type from mass assignment. (default: true)
# protect_sensitive_fields: true
# Raise an error when performing a #find and the document is not found.
# (default: true)
raise_not_found_error: false
# Raise an error when defining a scope with the same name as an
# existing method. (default: false)
scope_overwrite_exception: false
# Skip the database version check, used when connecting to a db without
# admin access. (default: false)
# skip_version_check: false
# Use Active Support's time zone in conversions. (default: true)
# use_activesupport_time_zone: true
# Ensure all times are UTC in the app side. (default: false)
# use_utc: false
test:
sessions:
default:
database: blog_test
hosts:
- localhost:27017
options:
consistency: :strong
# In the test environment we lower the retries and retry interval to
# low amounts for fast failures.
max_retries: 1
retry_interval: 0
Controller
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
render json: #user
end
* UPDATE **
fixed a null response (not in a json format) going out by doing this:
def show
#user = User.find(params[:id])
if #user.nil?
#user = []
end
render json: #user
end

your structure of yml is wrong
has to be -
development:
sessions:
options:
#raise_not_found_error has to be not here but see below
options: #strictly 2 spaces before
raise_not_found_error: false #strictly 4 spaces before not 6
so, raise_not_found_error parameter has to be child of development>options, not development>sessions>options

For me even correct indenting didn't work, what did is to create an initializer file called mongoid.rb in config/initializers/ and put this into it
Mongoid.raise_not_found_error = false

To save someone few minutes, if you are still having a problem and you are sure your mongoid.yml configs are correct, try to stop spring server as it seems to do a lot of caching!
$ spring stop

Related

Reduce the execution time of jobs of sidekiq

I am currently working on an app which involves syncing of contacts on rails server. I am using redis server and sidekiq for performing contact syncing in the background. My database is mongodb and I am using mongoid gem as ORM. Workflow is a follows:
Contacts on the phone are passed to the rails server through app and then on the rails server, it is queued in the redis server.
Now cron job triggers sidekiq which connects to redis and completes the job.
One Job of sidekiq is as follows:
it has array of contacts(size upto 3000).
It has to process each of these contacts. By processing I mean make insert queries to DB.
Now the problem is that sidekiq takes insane amount of time to complete the job. On average it takes 50-70 sec to complete the job.
Following are the relevant files
sidekiq.yml
# Sample configuration file for Sidekiq.
# Options here can still be overridden by cmd line args.
# sidekiq -C config.yml
:verbose: true
:concurrency: 5
:logfile: ./log/sidekiq.log
:pidfile: ./tmp/pids/sidekiq.pid
:queues:
- [new_wall, 1]#6
- [contact_wall, 1]#7
- [email, 1]#5
- [gcm_chat, 1]#5
- [contact_address, 1]#7
- [backlog_contact_address, 5]
- [comment, 7]
- [default, 5]
mongoid.yml
development:
# Configure available database sessions. (required)
sessions:
# Defines the default session. (required)
default:
# Defines the name of the default database that Mongoid can connect to.
# (required).
database: "<%= ENV['DB_NAME']%>"
# Provides the hosts the default session can connect to. Must be an array
# of host:port pairs. (required)
hosts:
- "<%=ENV['MONGOD_URL']%>"
#username: "<%= ENV['DB_USERNAME']%>"
#password: "<%= ENV['DB_PASSWORD']%>"
options:
#pool: 12
# Change the default write concern. (default = { w: 1 })
# write:
# w: 1
# Change the default consistency model to primary, secondary.
# 'secondary' will send reads to secondaries, 'primary' sends everything
# to master. (default: primary)
# read: secondary_preferred
# How many times Moped should attempt to retry an operation after
# failure. (default: The number of nodes in the cluster)
# max_retries: 20
# The time in seconds that Moped should wait before retrying an
# operation on failure. (default: 0.25)
# retry_interval: 0.25
# Configure Mongoid specific options. (optional)
options:
# Includes the root model name in json serialization. (default: false)
# include_root_in_json: false
# Include the _type field in serializaion. (default: false)
# include_type_for_serialization: false
# Preload all models in development, needed when models use
# inheritance. (default: false)
# preload_models: false
# Protect id and type from mass assignment. (default: true)
# protect_sensitive_fields: true
# Raise an error when performing a #find and the document is not found.
# (default: true)
# raise_not_found_error: true
# Raise an error when defining a scope with the same name as an
# existing method. (default: false)
# scope_overwrite_exception: false
# Use Active Support's time zone in conversions. (default: true)
# use_activesupport_time_zone: true
# Ensure all times are UTC in the app side. (default: false)
# use_utc: false
test:
sessions:
default:
database: db_test
hosts:
- localhost:27017
options:
read: primary
# In the test environment we lower the retries and retry interval to
# low amounts for fast failures.
max_retries: 1
retry_interval: 0
production:
# Configure available database sessions. (required)
sessions:
# Defines the default session. (required)
default:
# Defines the name of the default database that Mongoid can connect to.
# (required).
database: "<%= ENV['DB_NAME']%>"
# Provides the hosts the default session can connect to. Must be an array
# of host:port pairs. (required)
hosts:
- "<%=ENV['MONGOD_URL']%>"
username: "<%= ENV['DB_USERNAME']%>"
password: "<%= ENV['DB_PASSWORD']%>"
pool: 10
options:
# Configure Mongoid specific options. (optional)
options:
Model.rb
def retry_save_contact_dump(c_dump_id)
c_dump = ContactDump.where(_id: c_dump_id, status: ContactDump::CONTACT_DUMP_CONS[:ERROR]).first
return false if c_dump.blank?
user = User.where(_id: c_dump.user_id).first
puts "retry_save_contact_dump"
user.save_contacts_with_name(c_dump.contacts)
c_dump.status = ContactDump::CONTACT_DUMP_CONS[:PROCESSED]
c_dump.error_msg = ""
c_dump.save
rescue => e
c_dump.status = ContactDump::CONTACT_DUMP_CONS[:CANTSYNC]
c_dump.error_msg = e.message
c_dump.save
end
def save_contacts_with_name(c_array)
m_num = Person.get_number_digest(self.mobile_number.to_s)
c_array.each do |n|
next if m_num == n["hash_mobile_number"]
p = Person.where(h_m_num: n["hash_mobile_number"]).first_or_create
save_friend(p) #if p.persisted?
p.c_names.create(name: n["name"], user_id: self.id)
end
end
ContactDump.rb
class ContactDump
include Mongoid::Document
include Mongoid::Timestamps::Created
include Mongoid::Timestamps::Updated
field :contacts, type: Array
field :status, type: Integer, default: 0
field :user_id, type: BSON::ObjectId
field :error_msg, type: String
CONTACT_DUMP_CONS = {FRESH: 0, PROCESSED: 1, ERROR: 2, CANTSYNC: 3}
end
How can I speed up the processing of jobs? I tried with permutation of increasing concurrency of sidekiq in sidekiq.yml and pool of mongoid.yml, but no help.
How do whatsApp and other messaging apps deal with contact syncing?
If some other info is required, please ask. Thanks.
EDIT: If not possible to answer this question, can anyone please suggest me other ways to sync the contacts on the rails server.
indexes to the rescue.
class ContactDump
index({status: 1})
end
class Person
index({h_m_num: 1})
end
Person might need more indexes depending on what your Person.get_number_digest does.
After adding indexes run
rake db:mongoid:create_indexes
Also, do remove the puts, you don't need that on your worker and puts is hitting your performance badly, even when you can't see the output!

rails custom_configuration gem produces empty orderedoptions

Ruby 2.1.5
Rails 4.0.13
Using the custom_configuration gem, I get unexpected results.
config/environments/development.rb
JumboSIP::Application.configure do
# Settings specified here will take precedence over those in config/application.rb.
module Devise
module LdapAdapter
def self.valid_credentials?(login, password)
return true
end
end
end
config.cache_store = :memory_store
config.log_level = :debug
config.assets.compile = true
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
[..etc]
# ------------------------------------
# Application-specific configuration
# ------------------------------------
# use active directory auythentication (only for production)
config.x.use_ad_auth = false
# Enable to create cockpit cache files
config.x.cockpit_cache_enabled = false
config/initializers/scheduler.rb
if Rails.configuration.x.cockpit_cache_enabled
Rails.logger.info 'Initializing Cockpit Cache Scheduler'
puts 'Initializing Cockpit Cache Scheduler'
The code in the if is reached while it should not.
Debug inspection shows that
Rails.configuration.x.cockpit_cache_enabled evaluates to Empty ActiveSupport:OrderedOptions.
Rails.configuration.x is of type CustomConfiguration::Configuration
I checked I am actually in development environment.
Any clue as to why this happens? Any conflicts with other gems?
If I uses orderedoptions outside this gem, behaviour is as expected
It's two months delayed, but I ran into the same issue. The custom_configuration gem expects the options to be namespaced under another hash. Instead of:
config.x.cockpit_cache_enabled = false
try:
config.x.cockpit.cache_enabled = false
Now you should be able to access the value with:
Rails.configuration.x.cockpit.cache_enabled

deploy rails app that uses devise on heroku with mongohq

my app uses devise and mongo so i added mongohq as an addon but when it try to open my app on heroku i get this error :
An error occurred in the application and your page could not be
served. Please try again in a few moments.
If you are the application owner, check your logs for details.
heroku log :
2014-05-23T14:58:38.601715+00:00 app[web.1]: /app/vendor/bundle/ruby/2.0.0/gems/mongo-1.10.1/lib/mongo/mongo_client.rb:422:in `connect': Failed to connect to a master node at localhost:27017 (Mongo::ConnectionFailure)
2014-05-23T14:58:38.580675+00:00 app[web.1]: There is a configuration error with the current mongoid.yml.
2014-05-23T14:58:38.580684+00:00 app[web.1]:
2014-05-23T14:58:38.580686+00:00 app[web.1]: Problem:
2014-05-23T14:58:38.580688+00:00 app[web.1]: No sessions configuration provided.
2014-05-23T14:58:38.580690+00:00 app[web.1]: Summary:
2014-05-23T14:58:38.580692+00:00 app[web.1]: Mongoid's configuration requires that you provide details about each session that can be connected to, and requires in the sessions config at least 1 default session to exist.
2014-05-23T14:58:38.580693+00:00 app[web.1]: Resolution:
2014-05-23T14:58:38.580695+00:00 app[web.1]: Double check your mongoid.yml to make sure that you have a top-level sessions key with at least 1 default session configuration for it. You can regenerate a new mongoid.yml for assistance via `rails g mongoid:config`.
2014-05-23T14:58:38.580697+00:00 app[web.1]:
2014-05-23T14:58:38.580698+00:00 app[web.1]: Example:
2014-05-23T14:58:38.580700+00:00 app[web.1]:   development:
2014-05-23T14:58:38.580701+00:00 app[web.1]:     sessions:
2014-05-23T14:58:38.580703+00:00 app[web.1]:       default:
2014-05-23T14:58:38.580704+00:00 app[web.1]:         database: mongoid_dev
here's my mongoid.yml:
development:
# Configure available database sessions. (required)
sessions:
# Defines the default session. (required)
default:
# Defines the name of the default database that Mongoid can connect to.
# (required).
database: healthy_grocery_development
# Provides the hosts the default session can connect to. Must be an array
# of host:port pairs. (required)
hosts:
- localhost:27017
options:
# Change whether the session persists in safe mode by default.
# (default: false)
# safe: false
# Change the default consistency model to :eventual or :strong.
# :eventual will send reads to secondaries, :strong sends everything
# to master. (default: :eventual)
# consistency: :eventual
# How many times Moped should attempt to retry an operation after
# failure. (default: 30)
# max_retries: 30
# The time in seconds that Moped should wait before retrying an
# operation on failure. (default: 1)
# retry_interval: 1
# Configure Mongoid specific options. (optional)
options:
# Configuration for whether or not to allow access to fields that do
# not have a field definition on the model. (default: true)
# allow_dynamic_fields: true
# Enable the identity map, needed for eager loading. (default: false)
# identity_map_enabled: false
# Includes the root model name in json serialization. (default: false)
# include_root_in_json: false
# Include the _type field in serializaion. (default: false)
# include_type_for_serialization: false
# Preload all models in development, needed when models use
# inheritance. (default: false)
# preload_models: false
# Protect id and type from mass assignment. (default: true)
# protect_sensitive_fields: true
# Raise an error when performing a #find and the document is not found.
# (default: true)
# raise_not_found_error: true
# Raise an error when defining a scope with the same name as an
# existing method. (default: false)
# scope_overwrite_exception: false
# Skip the database version check, used when connecting to a db without
# admin access. (default: false)
# skip_version_check: false
# User Active Support's time zone in conversions. (default: true)
# use_activesupport_time_zone: true
# Ensure all times are UTC in the app side. (default: false)
# use_utc: false
test:
sessions:
default:
database: healthy_grocery_test
hosts:
- localhost:27017
options:
consistency: :strong
# In the test environment we lower the retries and retry interval to
# low amounts for fast failures.
max_retries: 1
retry_interval: 0
production:
sessions:
default:
uri: <%= ENV['MONGOHQ_URL'] %>
options:
skip_version_check: true
safe: true

Mongodb in rails:Could not connect to a primary node for a replica

I am new to rails and mongodb. i have generated mongod model in my rails project name as Forum
when i am trying to add record using following commands in rails console
f = Forum.new
f.topic_name = "my_topic"
f.save
I am getting following error
Moped::Errors::ConnectionFailure: Could not connect to a primary node for replic
a set #<Moped::Cluster:25470936 #seeds=[<Moped::Node resolved_address=nil>]>
I am running mongod server on port 27017
following is my mongoid.yml file
development:
# Configure available database sessions. (required)
sessions:
# Defines the default session. (required)
default:
# Defines the name of the default database that Mongoid can connect to.
# (required).
database: local
# Provides the hosts the default session can connect to. Must be an array
# of host:port pairs. (required)
hosts:
- localhost:27017
options:
# Change the default write concern. (default = { w: 1 })
# write:
# w: 1
# Change the default consistency model to primary, secondary.
# 'secondary' will send reads to secondaries, 'primary' sends everything
# to master. (default: primary)
# read: secondary_preferred
# How many times Moped should attempt to retry an operation after
# failure. (default: 30)
# max_retries: 30
# The time in seconds that Moped should wait before retrying an
# operation on failure. (default: 1)
# retry_interval: 1
# Configure Mongoid specific options. (optional)
options:
# Includes the root model name in json serialization. (default: false)
# include_root_in_json: false
# Include the _type field in serializaion. (default: false)
# include_type_for_serialization: false
# Preload all models in development, needed when models use
# inheritance. (default: false)
# preload_models: false
# Protect id and type from mass assignment. (default: true)
# protect_sensitive_fields: true
# Raise an error when performing a #find and the document is not found.
# (default: true)
# raise_not_found_error: true
# Raise an error when defining a scope with the same name as an
# existing method. (default: false)
# scope_overwrite_exception: false
# Use Active Support's time zone in conversions. (default: true)
# use_activesupport_time_zone: true
# Ensure all times are UTC in the app side. (default: false)
# use_utc: false
test:
sessions:
default:
database: local
hosts:
- localhost:27017
options:
read: primary
# In the test environment we lower the retries and retry interval to
# low amounts for fast failures.
max_retries: 1
retry_interval: 0
what to do??
review the localhost map in your hosts file or try hosts as 0.0.0.0:27017.
Information about host file: http://en.wikipedia.org/wiki/Hosts_(file)

Multiple LDAP Connections With Devise

I'm trying to modify an existing rails application that uses devise to check against an LDAP connection. I need to check against multiple different LDAP connections. Basically my user base is split between 2 or 3 different active directories and I'd like to be able to supply an array of connection information objects and have it run through the connections until it gets a response or fails. Is this possible with devise?
It is! Kind of. I hacked together a solution recently, not sure if it will be much help to you now.
First, you need to use devise_ldap_authenticatable. Once you have this installed, you can make some updates to the initialize method in the connection.rb file in this gem to accept either one configuration or many.
def initialize(params = {})
ldap_configs = YAML.load(ERB.new(File.read(::Devise.ldap_config || "#{Rails.root}/config/ldap.yml")).result)[Rails.env]
ldap_configs = ldap_configs.is_a?(Hash) ? [ldap_configs] : ldap_configs
The next part is up to you. Due to my constraints (usernames existing in both directories), I forced a user to enter a valid domain before looping through the connections. You might not have this constraint. In either case, just loop through the configs. Once you bind successfully, break the loop. The config values will be stored in the #ldap variable that is initialized here -
ldap_configs.each do |ldap_config|
#Maybe not needed if you don't have usernames in each directory. #domain is a user-entered value
if #domain == ldap_config["domain"]
#This should all stay the same, until you check the bindings
if #ldap.bind
#If it binds, break the loop. the values in #ldap will be stored
break
else
#keep looping
end
end
end
Next, make sure the ldap.yml file that devise_ldap_authenticatable generated is configured with all of your connections, including the domain, if needed -
## Environment
development:
-
host: "localhost1.com"
port: "389"
attribute: uid
base: dc=my-domain,dc=com
admin_user: cn=admin,dc=my-domain,dc=com
admin_password: admin_password
ssl: false
domain: "FIRST"
-
host: "localhost2.com"
port: "389"
attribute: uid
base: dc=my-domain,dc=com
admin_user: cn=admin,dc=my-domain,dc=com
admin_password: admin_password
ssl: false
domain: "SECOND"
I built on Steve's answer with the following that seems to work well. The benefit with this is that it wraps the original code and adds functionality to it. You can keep the ldap.yml file the same and add a hosts key with an array of hosts to the YAML to exercise this.
Note that I rescue the connection error in the loop. It will still throw when it attempts, again, to make the connection that the library would already try to make.
module Devise
module LDAP
module ConnectionExtensions
def initialize(params = {})
super
ldap_config = YAML.load(File.read("#{Rails.root}/config/ldap.yml"))[Rails.env]
ldap_config["hosts"]&.each do |host|
begin
#ldap.host = host
break if #ldap.bind
rescue Net::LDAP::Error => e
DeviseLdapAuthenticatable::Logger.send(e)
next
end
end
end
end
class Connection
prepend ConnectionExtensions
end
end
end
And here is the sample YAML file:
development:
host: localhost1.com
hosts:
- localhost1.com
- localhost2.com
port: 389
attribute: uid
base: dc=my-domain,dc=com
admin_user: cn=admin,dc=my-domain,dc=com
admin_password: admin_password
ssl: false

Resources