Rails: controller cannot recognize class from module/namespace - uninitialized constant - ruby-on-rails

I've created directory for API logic: app/api/EtherumAPI/V1 and put there following code:
module EtherumAPI
module V1
class Request
class << self
def trancation
end
end
end
end
end
Registered in my application.rb:
config.autoload_paths << "#{Rails.root}/app/api"
config.eager_load_paths << "#{Rails.root}/app/api"
And try to call it inside my controller:
def index
#test = EtherumAPI::V1::Request
#test.trancation
end
But I got this error:
uninitialized constant HomeController::EtherumAPI
I tried also something like "include EtherumAPI::V1" but it didn't succeed as well. How can I fix it and be able to call methods from Request class?

First off you can get rid of:
config.autoload_paths << "#{Rails.root}/app/api"
config.eager_load_paths << "#{Rails.root}/app/api"
All the subdirectories of app are by default auto-load paths. Occasionally the auto-loader gets "stuck" and will not pick up newly added directories. You can usually fix that by restarting the rails server and spring ($ spring stop).
There are two issues at play here. The first is inflection. Rails inflects file names from classes by camelizing the class name. Unfortunately this does not work automatically for acronyms as ABC -> a_b_c.rb.
So for the autoloader to look for EtherumAPI in etherum_api.rb you need to add an inflection:
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'EtherumAPI'
end
The second issue is that the module names must match the actual path to the file.
# app/api/etherum_api/v1/request.rb
module EtherumAPI
module V1
class Request
class << self
def trancation
end
end
end
end
end

Related

Rails can't find my classes after a while

I have a custom module with a class in Rails. I put this in my autoload inside the application.rb
config.autoload_paths << "#{Rails.root}/classes"
The module has a reference to a file in a deeper folder:
a.rb
require_relative './b/b.rb'
module A
def self.abc content
return A::B.new
end
end
B has nothing fancy:
b.rb
module A
class B
def initialize
end
end
end
What's happening right now is that in the beginning this works perfectly, but after some requests, or a certain amount of time, it stops working and I get an: uninitialized constant A::B error.
Any ideas? The fact that it works in the beginning is confusing me. Thanks in advance.

Using Libraries in Rails (4.1.x) Engines?

So the core issue at heart here is the following message:
`<class:ApplicationController>': uninitialized constant Xaaron::Core (NameError)
So I think some of the steps I have done will be redundant, but I am new to trying to add code to my library folder in a rails engine, in rails its rather easy. But here its not so much.
So here is what I have done:
in:
xaaron/
lib/
xaaron/
I have a directory called core/ with a file called loder.rb.
Inside of core is a directory called controllers and in side there is a file called user_controller which looks like:
module Xaaron
module Core
module UserController
def assign_to_member_group(user)
memeber = Xaron::Group.find('member')
user.add_group = memeber.group_name
end
end
end
end
To load this I have a loader file:
module Xaaron
module Core
module Loader
include Xaaron::Core::Controllers::UserController
end
end
end
Which I do not think is needed because in the engine.rb file I do: config.autoload_paths << File.expand_path("../xaaron/core/**", __FILE__) which just goes up one directory to the lib/ directory and loads xaaron/core/ and everything in it (or so I thought).
This loader.rb file is included in the ApplicationController
module Xaaron
class ApplicationController < ActionController::Base
...
include Xaaron::Core::Loader
...
end
end
So:
Whats the proper way to load my "core" library
Why am I getting the error above?
I guess your problem is with config.autoload_paths << File.expand_path("../xaaron/core/**", __FILE__). It expands into smth like Rails.root/lib/engine_name/xaaron/core/** and your lib path should be Rails.root/lib/xaaron/core. So, in your case, lib path should be config.autoload_paths << File.expand_path("../../xaaron/core", __FILE__)
Moreover, beeing within your ApplicationController, it is enough to include include Core::Loader, because you're already within Xaaron namespace.
Before you'll start working with controllers, try just call your module Xaaron::Core::Loader within rails console.

Reuse methods in a Rails generator

I'm writing a series of Rails generators that will share several of the same methods. I would like to abstract these methods into a module or class of their own to be reused (but not automatically fired) within each of my generators.
My latest attempt was to autoload a helper file and later include it:
lib/my_gem/engine.rb
module MyGem
class Engine < Rails::Engine
config.autoload_paths += Dir["#{config.root}/lib/helpers/**"]
end
end
lib/helpers/generators_helper.rb
module MyGem
module GeneratorsHelper
def some_method
# ...
end
end
end
lib/generators/my_gem/my_generator.rb
# ...
include MyGem::GeneratorsHelper
# ...
But I'll see something like Error: uninitialized constant MyGem::GeneratorsHelper.
I was able to accomplish this by manually requiring the file and then including the module. It's a little ugly, but keeps me from duplicating helper methods:
lib/my_gem/generators/my_generator.rb
require "#{Gem::Specification.find_by_name("my_gem").gem_dir}/lib/helpers/generators_helper.rb"
include MyGem::GeneratorsHelper

How to use modules in Rails application

I just created a module location.rb inside /lib folder with following contents:
module Location
def self.my_zipcode()
zip_code = "11215"
end
end
And now in my controller i am trying to call "my_zipcode" method:
class DirectoryController < ApplicationController
def search
require 'location'
zip_code = Location.my_zipcode()
end
end
But it throws an error:
undefined method `my_zipcode' for Location:Module
You can also add the following to your config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
And it should autoload your module without having to restart rails.
You might have to restart the rails server for it to recognize stuff in the lib directory.

Using classes in a module from the lib directory - Rails 3

I have a setup in the lib directory like so:
lib/
copy_process.rb
copy_process/
processor.rb
The copy_process.rb and processor.rb contain the module definition CopyProcess. The copy_process.rb defines the CopyFile class as well:
module CopyProcess
class CopyFile
end
end
The processor.rb is structured like so:
module CopyProcess
class Processer
end
end
In one of its methods, it creates a new copy file object:
def append_file_if_valid(file_contents, headers, files, file_name)
unless headers
raise "Headers not found"
else
files << CopyProcess::CopyFile.new()
end
end
When I used these files as part of a command line ruby program, it worked fine. However, i started putting it into a rails app, and I have written cucumber/capybara tests to hit the buttons and so forth where this is used. I initialize a Processor object from one of my AR models, and call the above method a few times. It cannot seem to find the CopyFile class, even though I have the following code in my application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Any ideas?
===============================================================
Edit Above was solved by extracting the copy file class into it's own file under lib.
I now have another issue:
The CopyFile class refers to module-level helper methods that sit in lib/copy_process.rb, like so:
module CopyProcess
# Gets the index of a value inside an array of the given array
def get_inner_index(value, arr)
idx = nil
arr.each_with_index do |e, i|
if e[0] == value
idx = i
end
end
return idx
end
def includes_inner?(value, arr)
bool = false
arr.each { |e| bool = true if e[0] == value }
return bool
end
# Encloses the string in double quotes, in case it contains a comma
# #param [String] - the string to enclose
# #return [String]
def enclose(string)
string = string.gsub(/\u2019/, '’')
if string.index(',')
return "\"#{string}\""
else
return string
end
end
end
When I run my cucumber tests, i get the following error:
undefined method `includes_inner?' for CopyProcess:Module (NoMethodError)
./lib/copy_process/copy_file.rb:64:in `set_element_name_and_counter'
Which refers to this method here:
def set_element_name_and_counter(element_names, name)
if !CopyProcess::includes_inner?(name, element_names)
element_names << [name, 1]
else
# if it's in the array already, find it and increment the counter
current_element = element_names[CopyProcess::get_inner_index(name, element_names)]
element_names[CopyProcess::get_inner_index(name, element_names)] = [current_element[0], current_element[1]+1]
end
element_names
end
I also tried moving the copy_file.rb and other files in the lib/copy_process/ directory up a level into the lib directory. I then received the following error:
Expected /Users/aaronmcleod/Documents/work/copy_process/lib/copy_file.rb to define CopyFile (LoadError)
./lib/processor.rb:48:in `append_file_if_valid'
The line that the error states creates an instance of CopyFile. I guess rails doesn't like loading the files in that fashion, and for the former setup, I think the copy_file.rb is having issues loading the rest of the module. I tried requiring it and so forth, but no luck. You can also find my most recent code here: https://github.com/agmcleod/Copy-Process/tree/rails
First config.autoload_paths += %W(#{config.root}/lib) should be sufficient. This tells rails to start looking for properly structured files at /lib.
Second, I think that you're running into issues because CopyFile isn't where rails expects it to be. As far as I know your setup 'should' work but have you tried seperating CopyFile out into its own file under the copy_process folder? My guess is that since the copy_process folder exists, it is expecting all CopyProcess::* classes to be defined there instead of the copy_process.rb.
EDIT: You may consider opening another question, but the second half of your question is a different problem entirely.
You define methods in your module like so,
module X
def method_one
puts "hi"
end
end
Methods of this form are instance methods on the module, and they have very special restrictions. For instance, you can not access them from outside the module definition (I'm skeptical how these worked previously). Executing the above gives
> X::method_one
NoMethodError: undefined method `method_one' for X:Module
If you want to access these methods from other scopes you have a few options.
Use Class Methods
module X
def self.method_one
puts "hi"
end
end
X::hi #=> "hi"
Use Mixins
module X
module Helpers
def method_one
puts "hi"
end
end
end
class CopyFile
include X::Helpers
def some_method
method_one #=> "hi"
self.method_one #=> "hi"
end
end

Resources