Unable to initialize class in Rails App - ruby-on-rails

Directory:
Prototype
-app
-assets
-controllers
---welcome_controller.rb
domainobjects
---SimilarJob.rb
Utilities
--API.rb
Controller Code
require_relative '../domainobjects/SimilarJob'
class WelcomeController < ApplicationController
def index
foo = API.new('DEVKEY')
res = foo.RetrieveFacts("Test", "Me")
#newResult = SimilarJob.new("test") <-- Failing Line!!!
render :text => res["Response"]["IsInternationalResponse"]
end
end
Object Code
class SimilarJob
end
I stripped out some things, but the API class exists in a separate directory, "Utilities", and for some reason I don't even have to reference it using the "requires_relative" keyword. It's a wrapper class that includes HTTParty and makes a successful GET request to my external API every time. Can someone explain why I seemingly don't have to reference it anywhere?
Alternatively, attempting to initialize the SimilarJob class fails each time. The error is:
uninitialized constant WelcomeController::SimilarJob
From what I researched here and on the web, this means I'm not referencing the file correctly. To test this out, I tried naming it incorrectly in the "requires_relative" statement and the framework informs me that the requested file could not be loaded. So it seems like Rails is finding my class, it just won't initialize it for some reason.
The most maddening part is that I'll make a few small changes to SimilarJob, restart my server, and it'll work all of a sudden. If I stop and start the server again, it's back to the error I pasted below.
This is my first time really digging in something other than .NET MVC or KnockoutJS..would you guys mind pointing out the error of my ways?
EDIT: I used the generate command for this controller, so all views and routes work appropriately. In fact, if I comment out the problematic line, the property I'm referencing on the last line in my JSON response renders to the file just fine.
EDIT v2: Strangely enough..changing my class name to Jobs (one word) is getting rid of this error. This comes off as bizarre! Can anyone confirm that this is my issue?

Names matter, and you've named your file wrong. SimilarJob.rb needs to be similar_job.rb.
Similarly, your API file should be called api.rb, and the class it defines should be called Api. This stuff is important, as you've deviated badly from Rails convention, and are suffering for it.

Related

Ruby getting undefined Method error, and i am not sure if i fully understand how methods are working for my plugin

i am trying to create a plugin for Discourse, which is written in Ruby. As normal blank files my program is working perfect and without errors, but when i try to adapt my code into the plugin context i run into issues and i am not sure if i really understand how the whole idea with functions is meant to be.
I thought it would be smart to have more than just one file, to outsource functionality in different methods and require them in a kind of "main" file. For example getting tweets is one method in an extra file, sending tweets a different method in another file. In blank ruby code its working fine but when i try to integrate that into the plugin file structure i get the error
undefined method `my_method' for #<Plugin::Instance:0x00007f9004012fc0> (NoMethodError)
the files with the methods are in a lib directory and the "main" file which is called the plugin.rb is in the mainfolder
so i tried
require_relative 'lib/my_method'
and the other way
require_relative File.expand_path('../lib/my_method.rb', __FILE__)
but i still run into that error.
i have not defined any kind of classes or modules or something like that so the "method files" are literally starting with
def self.my_method
#my code here
end
Could that be the reason why i run into the error above? Why is it working as blank ruby code, but not when i try to run the plugin with rails s on my discourse instance?
I am still pretty new into ruby programming, so maybe my question seems a bit silly.
Here is the link which lead me threw the plugin creation:
https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins-part-1/30515
Unfortunately, your understanding of methods is shallow. Basically, any method you declare in the global scope is added to the Object class as private method, so it is accessible everywhere in your objects cause they derive from Object class and in global scope because it is the scope of the Object class. If you declare method as self.method, you make it a method of main Object, because self refers to main, which is not the desired behaviour for you. To fix that issue, you should just remove self and write it like that:
def my_method
end
This way this method will be added to the Object class itself, not the main Object. There is a link on the article about methods in general. And another one on the toplevel scope behaviour. In this codepen you may observe the difference. Also, it may be useful for you to learn some Ruby before going on with your development. I suggest rubymonk. Another issue is your one-method files which is not the best practice for ruby code organization. Ruby is truly object-oriented language and if you need to have a bunch or even one general-purpose method, it is better to put it in a module or class to define its purpose and role in application, make it reusable and trackable, without global scope pollution.

How Rails understands what request is?

So, I wrote this code:
module UniversityFinder
def define_shortcut_part
r=request
subs=request.subdomains
if subs.length>1
subs[1]
else
subs[0]
end
end
def university
university=University.find_by_shortcut(define_shortcut_part)
end
end
Which suits my one needs, in separate file, and included module in one of my controllers.
The thing is, that I expected uninitialized constant error from Rails for this request variable.
On the opposite, it works fine and does what I wanted.
This is purely curiosity question regarding Rails source code ('rails magic') for better understanding. This variable nor even called like instance variable (#request), but still Rails gets this local. Can someone explain how it works?

Double colon in class name and RubyMine complaints about short name

I have the following autogenerated controller in
conrollers/v2/base_controller.rb.
class V2::BaseController < ApplicationController
end
It was generated by Versionist gem. I am trying to make a controller inherited from V2::BaseController. I wrote
class V2::MainController < V2::BaseController
def index
render :text => 'abcde'
end
end
It works fine and I can see my text rendered in browser. However, RubyMine IDE complains that the class name V2 in V2::MainController is too short and I should rename the class.
I am confused because I thought that V2:: means that we define a new class inside V2 module. If I am wrong, then why does RubyMine ignore the same problem with BaseController?
UPD: RubyMine complaint
RubyMine uses reek for code smell detection.
Warning it's giving you is called Uncommunicative Module Name.
Uncommunicative Module Name checks for:
1-character names
any name ending with a number
In your case warning was caused with 2 in V2. Even for Version2 it would be the same.
But it's actually only a recommendation. Ruby works fine with this code.
Nah, it's just a notice for you as a programmer. Short variable names are usually cryptic and less intention-revealing, so it's a nice check to have, but is definitely not a required one.
I think that V2 is perfectly fine for your case, but if you're still concerned, just rename it to Version2 to make Rubymine happy. I don't know if it will be still compatible with the gem you use. it seems Rubymine doesn't like any variable with a number on the end.
But why does IDE show the notice only for MainController?
I can think about 2 options here:
It's some glitch in RubyMine indexing. Or maybe it was made this way not to spam your file tree with red underlines (one is actually enough for you to notice that). Try restarting the IDE and see if it goes away.
RubyMine can't find definition of V2 module, because V2 in class V2::MainController is a reference to defined module somewhere, and not its definition. Solution: create the empty module and see if your warning goes away.
app/controllers/v2.rb
module V2
end

Ruby on Rails. Few classes in the same file. "Uninitialized constant" error

I've defined a few Exception classes in my app/models/core/exceptions.rb file:
class Core::Exception < Exception end
class Core::UserNotFoundException < Core::Exception end
...
Then added /config/initializers/require.rb file so Rails can find classes with names which don't meet file names:
require "#{Rails.root}/app/models/core/exceptions.rb"
When I start the app (development mode), everything works fine until I change anything to any .rb file. Then when I refresh browser page I get error "Uninitialzed constant Core::Exception". So every time I make any modification to the source code (except the views) I have to restart 'rails server'.
Any idea on why when I refresh a page my 'require' are no longer loaded? How to fix this?
Creating a core.rb file should help.
Just place the Core module definition there
# /app/models/core.rb
module Core
end
I believe the problem is the Core module. When you hit
class Core::Exception ...
rails needs to find the module or class named Core. Rails will create a module called Core automatically if it finds files with paths off the form 'core/foo.rb' in its autoload path (see the algorithm pseudo code in the guide on autoloading).
Because this Core module is autoloaded, code reloading will trigger its removal. A new Core module may be created, but this will no longer have the classes you had added to it.
One option would be to not fight Rails's code organisation and put those classes in individual files.
An alternative may be to change how you create those classes to
module Core
class Exception < ::Exception; end
end
Which means that the Core module won't be autoloaded and thus shouldn't be eligible for removal.

"Unrecognized type" error in haml view, but not console

I have a small library, say widget_utils.rb, that lives in the lib/ directory of the app. (I've set the config to autoload source files from lib/)
The utils include the 'spira' gem which does ORM mapping based on RDF.rb. In the widget_utils.rb file are class objects based on my RDF repository, and they refer to a type called Spira::Types::Native.
I have a static method in WidgetUtils that returns a hash based on RDF data for use in rendering, WidgetUtils.options_for_select.
If I launch the console, I can call WidgetUtils.options_for_select and get back my hash perfectly.
But if I run the server, and try to render /widget/1234 or /widget/1234/edit to show one widget, I get the error Unrecognized type: Spira::Types::Native
At the bottom of my stack trace is widget_controller.rb, and at some point the haml file is doing a "load" of "lib/widget_utils.rb", and crashing with the Unrecognized type at the point where it's referenced in the util source file.
From the console if I do "load 'lib/widget_utils.rb'" I get no error, the type is recognized successfully.
I'm stumped, and too new to rails to successfully come up with a strategy to solve this problem outside of trial and error.
As it turns out, this problem is specific to the Spira library I'm working with, and JRuby when serving pages.
Spira keeps its collected known RDF types in a "settings" hash that it makes thread local. In most ordinary circumstances on MRI Ruby/Rails this isn't an issue, since the requests are usually handled in the same thread as the Spira initialization.
Similar problems will occur under JRuby if you attempt to make data global through, for instance, class variables. Some other mechanism needs to be found to make global reference data available to all service threads. (Mutable shared data is not even something to consider unless you like headaches.)
There is a workaround for Spira that will keep its settings available. In my utility class I added this monkey patch to take the settings out of Thread.local:
module Spira
def settings
#settings ||= {}
end
module_function :settings
end

Resources