Rails 3.2.9 and models in subfolders - ruby-on-rails

Since rails 3.2.9 I'm unable to store models in subfolders. In my app I have this tree:
models
-type_models
-assets
-user
-concerns
Also in application.rb there is
config.autoload_paths += Dir["#{config.root}/app/models/*"]
All things was ok till rails 3.2.9. Now I have "Unknown constant" error.
I don't want to namespace tons of model and fix all app to use namespaced models.
Warning: Error loading /var/www/my_app/app/models/type_models/context_type.rb:
uninitialized constant TypeModels::ContextType
file context_type.rb:
class ContextType ... end

Try to use:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]

in config/application.rb:
config.autoload_paths += %W(type_models assets user concerns).map { |folder| "#{config.root}/app/models/#{folder}"}
in models/type_models/context_type.rb:
class TypeModels::ContextType < ActiveRecord::Base
...
end
Restart Rails and you're all set!

Wrap your class ContextType ... end to module:
module TypeModels
class ContextType
# blah blah
end
end

Related

undefined local variable or method for method located in lib directory file

I have some code i've inherited and am in the process of upgrading it to Rails 3.1. I'm suuuuper close to done but I got a bug.
In Rails Console I run User.first and I get this error
undefined local variable or method `acts_as_userstamp' for #<Class:0x000000046bef50>
Now acts_as_userstamp is a method located on line two inside my User model
class User < ActiveRecord::Base
#TODO /lib is not loading??? or is it??? why this method not work in browser?
acts_as_userstamp
And is defined in a file called app/lib/model_modifications.rb.
Now I recently discovered that my app/lib folder was not being autoloaded in my application.rb file and I think that's been fixed...or has it? Is this file correct? Or no?
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# evil outdated soap middleware, TODO: kill it with fire
# Does this have to be loaded BEFORE the first line???
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "soap4r"))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "plugins", "soap4r-middleware", "lib"))
# evil outdated soap middleware, TODO: kill it with fire
require 'soap4r-middleware'
require File.join(File.dirname(__FILE__), '..', 'app', 'lib', 'soap.rb')
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require *Rails.groups(:assets => %w(development test))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
module MyappDev
class Application < Rails::Application
# startup the lib directory goodies <-- IS THIS CORRECT???
# config.autoload_paths << "#{Rails.root}/lib"
# config.autoload_paths += %W( lib/ )
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
config.middleware.use MyAPIMiddleware
end
end
I'm trying to debug this file as I post this now. Here is a peak at it's internal structure...(i've just included the overall structure for the sake of brevity)
app/lib/model_modificatons.rb
class Bignum
...
end
class Fixnum
...
end
class ProcessorDaemon
...
end
module ActiveRecord
module UserMonitor
...
end
module MyLogger
...
end
end
class Object
...
end
class Struct
...
end
class String
...
end
class Fixnum
...
end
class OpenStruct
...
end
class ActiveRecord::Base
def self.visible_columns
...
end
...
def self.acts_as_userstamp
logger.info "HI fonso - acts_as_userstamp is called"
include ActiveRecord::UserMonitor
end
...
protected
def self.range_math(*ranges)
...
end
end
class Array
...
end
class DB
...
end
If you can spot a problem with the overall structure or anywhere else please let me know.
So why is this method not found? I'm trying to debug it as I'm posting this and I'm getting nothing.
I suspect the file app/lib/model_modifications.rb is not being loading. That nothing in the /lib directory is being loaded..but how do I confirm this?
Thank you for reading this far, I hope I've not rambled on too much.
autoload_path configuration does not load all the given files on the boot but defines folders where rails will be searching for defined constants.
When your application is loaded, most of the constants in your application are not there. Rails have a "clever" way of delaying loading the files by using a constant_missing method on Module. Basically, when Ruby encounters a constant in the code and fails to resolve it, it executes said method. THe sntandard implementation of this method is to raise UndefinedConstant exception, but rails overrides it to search all of its autoload_paths for a file with a name matching the missing constant, require it and then check again if the missing constant is now present.
So, in your code everything works as expected and you need to load this extension file manually. If you want to have some code that executes on the application boot, put your file within config/initializers folder.
Aside: Try avoiding monkey patching whenever possible. It might be looking clever, but adding more methods to already overpopulated classes will not make them easier to use.

Using Packwerk with ActiveAdmin (unitialized constant after moving model folder)

I'm using packwerk in my rails 6 application to enforce boundaries between new components (but I think the problem is more related to moving a model being used by active admin out of the app/models folder).
Old setup of rails project:
app/
...
models/
subscription.rb
...
services/
subscription_service.rb
bin
config
...
Becomes
app
bin
components/
subscription/
app/
public/
subscription_service.rb
spec/
subscription_service_spec.rb
package.yml
config
...
I then autoload the public files in my config/application.rb
class Application < Rails::Application
...
config.autoload_paths += Dir[Rails.root / "components/*/app/public"]
...
end
Now when I run bundle exec rspec components/subscriptions/spec/subscription_service_spec.rb the tests pass and all seems to work fine.
When I add the subscription model though so that structure will look like this:
app
bin
components/
subscription/
app/
public/
subscription_service.rb
models/
subscription.rb # no longer in app/models
spec/
subscription_service_spec.rb
package.yml
config
...
I get this error:
An error occurred while loading ./components/subscriptions/spec/subscription_service_spec.rb.
Failure/Error:
ActiveAdmin.register Subscription do
menu false
includes :pauses, :invoices
config.remove_action_item(:edit)
config.remove_action_item(:destroy)
filter :id
filter :status
NameError:
uninitialized constant Subscription
I think this has something to do with how ActiveAdmin autoloads perhaps, but I'm struggling to find an answer - so any help/clues would be much appreciated
Ah I figured it out, I forgot to import the models folder in application.rb which should now look like:
class Application < Rails::Application
...
config.autoload_paths += Dir[Rails.root / "components/*/app/public"]
config.autoload_paths += Dir[Rails.root / "components/*/models"]
...
end

Require module throwing error in Rails 5

I am attempting to create a permissions structure for users in my application. I created a permissions.rb file in the lib/ directory in my rails application.
When I try to include Permissions in my user model I am getting this error.
This is what I have in the user model.
class User < ApplicationRecord
include Permissions
...
end
How can I include this file and its methods without getting this error?
To include modules under lib folder you will need to add your lib folder in autoload_path in your application.rb
config.autoload_paths += %W( #{config.root}/lib/)
add this line in your application.rb.
I think it would be good if you use autoload file when application start then it would like to on the application.rb
config.autoload_paths << Rails.root.join('lib')
Or you can use user.rb
class User < ApplicationRecord
load File.join(Rails.root, 'lib', 'permissions.rb')
end
The module would look like this, always make sure the naming conventions is right like if run module name on the console with underscore then he would give your file name, see the below if your module name is Permissions then
Loading development environment (Rails 5.1.4)
2.3.4 :001 > "Permissions".underscore
=> "permissions"
your file name is permissions.rb
#=> permissions.rb
module Permissions
...
def self.method #=> method name instead of the method
#=> code staff here
end
or
def method #=> method name instead of the method
#=> code staff here
end
...
end
Hope it helps

Rails: Loading custom class from lib folder in controller

I've created a file as lib/services/my_service.rb.
# /lib/services/my_service.rb
class MyService
...
end
I want to use it in app/controllers/my_controller
class MyController < ApplicationController
def method
service = MyService.new()
end
I'm getting an error that MyService is an uninitialized constant. I've tried to import it with
require '/lib/services/my_service.rb'
But I'm getting
cannot load such file -- /lib/services/my_service.rb
Edit: I have tried autoloading from application.rb using
config.autoload_paths << Rails.root.join('lib')
But no dice. Still getting uninitialized constant MyController::MyService
Ruby on Rails requires following certain naming conventions to support autoloading.
Rails can autoload a file located at lib/services/my_service.rb if the model/class structure was Services::MyService.
Change your lib/services/my_service.rb to:
module Services
class MyService
# ...
end
end
And use that class like this in your controller:
service = Services::MyService.new
Please note that depending on your Ruby on Rails version, you might need to add the lib folder to the list of folders which are queried when looking for a file to autoload:
# add this line to your config/application.rb:
config.autoload_paths << "#{Rails.root}/lib"
Read more about autoloading in the Rails Guides.
You probably need to enable the autoload from the files in the lib/ folder:
# config/application.rb
config.autoload_paths << "#{Rails.root}/lib"
If you prefer to do it "manually", then you can only require such file in the same file:
# config/application.rb
require './lib/my_service'
After this a restart is necessary.
there is a setting in config/application.rb in which you can specify directories that contain files you want autoloaded.
From application.rb:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
or
config.autoload_paths += Dir["#{config.root}/lib/**/"]
rails 3
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end
Add this in your application.rb
config.eager_load_paths << Rails.root.join('lib/services')

config.autoload_paths not working, unable to include modules in rails 4

I have created a simple module and placed it in the lib directory and have included in the controller file.
below is the controller code.
class UserController < ApplicationController
include Departments
def create
user_data = Hash.new
user_data["data"] = "hello world!"
user_data["price"] = 12
render :json => user_data
end
end
when i try to execute it i see the below error
ActionController::RoutingError (uninitialized constant UserController:: Departments):
I have searched forums and see that adding
config.autoload_paths += %W(#{config.root}/lib)
solves the issue, but it did not in my case. I am using Rails 4.2.7.1 and ruby ruby 1.9.3p547.
Can anyone point out what could be the issue, Thanks.
I had the naming convestion wrong, i created a sub directory under the lib folder by the name of my module and then created the file with the class name.rb and it worked.
Reference: "Uninitialized constant" error when including a module

Resources