rails: using a class defined in another module - ruby-on-rails

I am getting the following error, when I try to run my application:
uninitialized constant RegistrationsController::User_serial
In my config/application.rb, I have:
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
In my registrations_controller.rb, I have the following:
class RegistrationsController < Devise::RegistrationsController
........
def create
#user = User.new(params[:user])
user_serial_local = User_serial.new #initialize class defined in lib/my_tools.rb
date_time_local = Date_formatter.new
......
In lib/my_tools.rb, I define some classes:
class User_serial
def self.calculate(first,last)
first_3 = first[0..2]
last_4 = last[0..3]
time = Time.now.to_i
return first_3 + last_4 + time.to_s
end
end
class Date_formatter
def self.datetime
return Time.now.strftime("%Y-%m-%d %H:%M:%S")
end
end
There are a lot of references to overriding a class, and instructions on how to insure that anything placed in the lib folder is included (followed in my code). Why am I getting the error message?

For rails' magic loading to work it needs to be able to find the file a class/module is defined in based only on the class name.
This in turn means sticking to rails' naming conventions and putting things where rails expects: UserSerial should be defined in user_serial.rb. You might be able to get User_serial to work as a class name but rails will never look in my_tools.rb for that class.

Related

Name error uninitialized constant module rails

I have a rails application in that I have modules inside /app/adapters/UDB/ folder. The module is not loading. I have added the following in application.rb
config.autoload_paths += Dir["#{config.root}/app/adapters/**/*"]
I am calling module from model file /models/userinvite.rb
def update_cassandra
ypusers = UDB::YpRewards.new.ypusers
ypusers.execute("UPDATE invitation_backlog SET invitation_code = '#{invitation_code}', invitation_sent_date = #{invitation_sent_date.to_i * 1000}, invited_by = '#{invited_by}' WHERE email_address = '#{email}'")
end
/app/adapters/UDB/yp_rewards.rb
module UDB
class YpRewards
def initialize
end
def ypusers
#ypusers ||= UDB::Connection.new.connection.connect('ypusers')
end
...
Please help me solving it.
I think the issue is with module name.
Your module name is UDB, then you can load this module by specifying its name in smallcase letters as per rails naming convention (camelcasing)
config.autoload_paths += %W( #{config.root}/app/adapters/u_d_b)
Try including the module in your UserInvite model,
include UDB
This is a good site to know more about the placement and usage of modules.

Can not call method of other class from static method

At first, i have a class which in app/workes/ like this:
class SendMailTask
include Resque::Plugins::Status
require 'mail'
def perform
...
end
And as a controller, i have class UsersController and a static method like bellow:
class UsersController < ApplicationController
def self.check
...
::SendMailTask.create(to: [] << #to_addresses, subject: #subject, body: #body)
end
When i call method UsersController.check() from other file, i received the error: "in `block in check': uninitialized constant SendMailTask (NameError)"
But from other controller, i can call SendMailTask normally:
class ErrorController < ApplicationController
def index
...
::SendMailTask.create(to: [] << #to_addresses, subject: #subject, body: #body)
end
I try to add this line:
config.autoload_paths += %W(#{config.root}/app/workers)
to application.rb and try to add
require './SendMailTask'
at the begin of file users_controller.rb but it does not work.
Please help me resolve this error. Thanks you
NameError means the your SendMailTask isn't loaded. so you will have to load that. so couple of things.
I noticed a typo workes, so please verify the file name is correct. By Convention, it should be located at app/workers/send_mail_task.rb. so kindly double-triple check the same.
About require './SendMailTask', this is wrong. Instead it would be send_mail_task as requires works on filenames & not class names.
if still get an error, then please post your $LOAD_PATH to see you are requiring the file relative to the defined $LOAD_PATH
Instead of require, I prefer to use require_dependency as it works with code-reloading etc. so if you have trouble with auto-loading, just stick that require_dependency on top of the file, this will hint rails to load the file BEFORE running the controller.

Cannot load Ruby Model under a namespace

I have a namespaced Post controller as below
class Admin::Blog::PostsController < Admin::BaseController
end
and a namespaced model as follows.
class Blog::Post < ActiveRecord::Base
end
But when I try to access the model inside the index action of the post controller as below
def index
#posts = Blog::Post.where(:foo_id => params[:id]).paginate(:page => params[:page], :per_page => 20)
end
I get the following error
LoadError at /admin/blog/posts
Expected/app/models/blog/post.rb to define Post
But when I move the model to Admin::Blog::Post namespace from Blog::Post is works.
I'm bit confused with this and not able to get what is going on with this.
Is it required that Controller and Model should be present in the same namespace ?
Following is the snippet from routes.rb
namespace :admin do
namespace :blog do
resources :posts
resources :categories
end
end
Blog module snippet
module Blog
def self.table_name_prefix
'blog_'
end
end
Preloading controllers and models
config.autoload_paths += Dir["#{Rails.root}/app/models/**/**"]
config.autoload_paths += Dir["#{Rails.root}/app/controllers/**/**"]
config.autoload_paths += Dir["#{config.root}/app/helpers/**/**"]
config.autoload_paths += Dir["#{config.root}/app/tags/**/**"]
config.autoload_paths += %W[ #{Rails.root}/app/extensions #{Rails.root}/app/modules #{Rails.root}/app/drops #{Rails.root}/app/filters #{Rails.root}/app/mailers ]
This is probably caused by rails' autoloader. When doing this :
module Foo
class Bar
end
end
And then trying to use Foo::Bar, the autoloader first tries to locate app/models/foo/bar.rb. The file is loaded, and module Foo is defined here (albeit as a module containing solely Bar) so the autoloader never attempts to load app/models/foo.rb.
This should only happen in development mode, as in production mode all of your files are require'd on startup.
There are two workarounds AFAIK :
Require the module
using require_dependency :
require_dependency 'foo'
module Foo
class Bar
end
end
This is IMHO the right solution, as it does not break the constant lookup, but it is also a bit annoying as you have to add the require statement on top of each namespaced file.
Create Custom Active record Base
This solution doesn't rely on autoloading. Set the models to inherit from the following, instead of from ActiveRecord::Base directly:
class CustomActiveRecordBase < ActiveRecord::Base
self.abstract_class = true
# If no table name prefix has been defined, include the namespace/module as
# table name prefix, e.g., Blog:: -> blog_
def self.table_name
# If a table_name_prefix has been defined, follow default behaviour
return super if full_table_name_prefix.present?
# Find the prefix, e.g., Blog::Post -> 'blog', User -> ''
prefix = model_name.name.deconstantize.underscore
# If no prefix, follow default behaviour
return super unless prefix.present?
# Otherwise add the prefix with an underscore
"#{prefix}_#{super}"
end
end
Then there is no need to define self.table_name_prefix in blog.rb.
This could all be done by monkey-patching ActiveRecord::Base, but this interferes with other classes, such as ActiveRecord::SchemaMigration, which doesn't have a table prefix.
Note :
This bug seems to have been resolved in rails 4. I used the second workaround a lot while on rails 3, but I've tried to reproduce the bug in rails 4 and it does not show up anymore. I think they modified the way the autoloader works... For more info, see the rails guides on autoloading and reloading constants

Creating custom reusable method in rails 4

Guys today I'm trying to create global method for all my project models in rails 4
I created something like that under this path lib/query.rb
module Query
def custom my_query
self.where(my_query)
end
end
then added this code in this file lib/application.rb to allow rails to load the files under this path
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
then included my method in my model by using this command
include Query
now should every thing ready to use my custom method , but when I tried to call my method in the controller like that
def index
#users= Users.custom(params[:query])
end
I got the error
undefined method `custom'
what I should do now ??
why i got this error ??
I think you should use concern for your module. Add your file in app/models/concerns.
# app/models/concerns/query.rb
module Query
extend ActiveSupport::Concern
included do
#you can use a scope
scope :my_query, ->(just_a_param){ .... }
end
module ClassMethods
#or a method
def self.another_query
where(....)
end
end
end
Of course you need to include the module in your model. As concern erd default in rails, you no longer need to change config autoload paths.
As a class method, you'll need the "self."
def self.custom my_query
self.where(my_query)
end
EDIT: If you want this in all ActiveRecord models, you can add it as an initializer
#config/initializers/active_record_extensions.rb
class ActiveRecord::Base
def self.custom my_query
self.where(my_query)
end
end
If you just want this on a single class, a concern would work.
In your example, there is no reference given between your class Users and your method custom. First: if Users refers to a Ruby on Rails class it is probably called User (see also comment of japed). So change the call. Next, your User class must inherited from ActiveRecord else it would not be aware of the existence of 'where'. For details check your app/models/user.rb
Then Swards' suggestion should work for you. Stop your application and restart. Now it should work.
Guys I found the true way to make it
First my impropriety was the include that I set in the model
It should be extend Query
then it will work well
so the true code will be
create your method file under this path lib/query.rb
then set this code in it
module Query
def custom my_query
self.where(my_query)
end
end
then added this code in this file lib/application.rb
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
then extend the method in the model by using this command
extend Query
and in your controller query you can use the method like that
def index
#users= Users.custom(params[:query])
end
This is my solution, not exactly the 'Rails way', but using some sort of decorator pattern:
#user = CustomQuery.find_for(User.find(params[:search])).perform!
class CustomQuery
attr_reader :params, :klass
def initialize(klass)
#params = params
#klass = klass
end
def self.find_for(params)
CustomQuery.new(params)
find_model_for(params.tap {})
end
def perform!
return params unless params.nil?
klass.all
end
def find_model_for(klass)
#klass = klass
end
end
While I'm not sure about the process to create a global method, I can tell that your Ruby code is not valid:
def custom my_query
self.where(my_query)
end
It would need to be:
def custom (my_query)
self.where(my_query)
end

Uninitialized Constant in Rails Controller

I have the following in my controller:
class SurveysController < ApplicationController
def index
survey_provider = FluidSurveysProviders::SurveyProvider.new
contact_lists = survey_provider.get_lists()
#survey = Survey.new(contact_lists)
end
And I'm receiving this error:
NameError in SurveysController#index
uninitialized constant SurveysController::FluidSurveysProviders
Excuse my Rails noobiness, I'm sure I'm leaving out something important here. But it seems to me that I am trying to "initialize" the constant with this line:
survey_provider = FluidSurveysProviders::SurveyProvider.new
But that's the same line that's throwing an error because it's not initialized. Where should I be "initializing" the Provider?
Once you require fluid_surveys_providers (or similar) then do this:
include FluidSurveysProviders
Make sure SurveyProvider is wrapped with module FluidSurveysProviders. It may look like this
module FluidSurveysProviders
class SurveyProvider
...
end
end
if its an ActiveRecord object try this
class FluidSurveysProviders::SurveyProvider < ActiveRecord::Base
...
end
The SurveyProvider was not loaded correctly.
For a quick fix, move the class file into app directory, e.g. app/lib/survey_provider.rb. Then all code inside app will be auto-loaded by Rails.
Or make sure the path to class SurveyProvider is included in the autoload_path of Rails. In config/application.rb
config.autoload_paths += %W(#{config.root}/lib) # where lib is directory to survery_provider
If you use Rails 5, be careful that autoload is disabled in production environment. Check this link for more info.

Resources