I have a class that looks like this:
module API
module MyNamespace
class Base < ActiveRecord::Base
end
end
end
module API
module MyNamespace
class MyClass < Base
end
end
end
When trying to upgrade from ruby 1.9.3 to 2.1.5, I started getting an error when executing the entire spec suite.
superclass must be a Class (Module given)
This is strange, because API::MyNamespace::Base is a class. Also if I run the tests as part of a smaller run (individual spec, or everything in the API namespace), then everything is fine.
I'm not really sure what to try here.
I think I hit this once and it's stupid. I think I changed it from actually using the words module API etc to just doing
class API::MyNamespace::MyClass
and it was happier with that (even though they're logically equivalent)
Related
I have a rails app which uses a ActiveRecord model defined in a rails engine. I want to add some methods to that class (in this case FormInstance), so I simply use the syntax:
class FormInstance
def mynewmethod
#..my code here..
end
end
But this doesn't seem to work. It does indeed create FormInstance class with the new method, but it's not extending the Engine class, all the original methods of the FormInstance class are gone. What's the correct way to do this?
Env: rail 3.2.13, ruby 2.0.0
You can do it with the decorator pattern. There are multiple ways of implementing it. Have a look at the activesupport-decorators gem. It hooks into Rails ActiveSupport and adds a convention to doing decorators that is safe from circular dependencies. We have been using it in production on multiple apps for a while.
https://github.com/EPI-USE-Labs/activesupport-decorators
[This is a follow-up question to "How I can modularize Rails model?"]
Is there anyway to organize classes in app/models directory of Rails?
Do I have to use single top-level namespace for all of the classes?
Initial motivation is, I want place business logic classes which do not inherited from ActiveRecord::Base into app/models directory. Searching this site reveals many answers which recommend to place business logics classes in the app/models directory. I posted a different question, and got recommendation that it is possible to place such classes into lib directory.
Now I'm curious. I'd like to place these classes into different namespace and directory in apps/models directory which recommended by others. Is it possible?
Actually, I experiment that, but it seems to me that is what rails is not expected. If I create such a class (like SomeModName::ClassInMod in some_mod_name/class_in_mod.rb ) it does not get loaded. Also, I defined constants inside the module. Since they're not loaded, I can't use them. Actually, with rspec it work without problem, but with rails server, the class does not loaded. I'm sure it is related to autoloading issue.
In addition to the classes mentioned above, classes inherited from ActiveRecord::Base can be placed into some namespaces inside a module. I'm curious whether this work well or not too.
So the question in other words: can I make rails happy by configuring these files to be loaded, or is not the way rails designed?
Yes, you can define an ActiveRecord class in a module. The easy way is to use the generator:
./script/rails generate model logic/phase_logic
./script/rails generate model logic/evaluation_logic
Observe, that Rails will create additionally a file with the definition of the module. In this case:
# app/models/logic.rb
module Logic
...
end
# app/models/logic/phase_logics.rb
class Logic::PhaseLogic < ActiveRecord::Base
...
end
# app/models/logic/evaluation_logics.rb
class Logic::EvaluationLogic < ActiveRecord::Base
...
end
Your problems with constants defined in the module were caused by the fact, that you defined the constants in the definition module "wrapped" around only one model, from the two you have created. A very important part in understanding ruby (and Rails) - especially for people who have strong background in compiled languages - is to remember that there is no compilation phase, so the definition of some class is read and executed only when that specific class is used. Sometimes a week after the application server has been started and served thousands of requests.
Thus, as I said in the previous question's answer, the problem with autoloading was that sometimes the definition of the constants was read after the definition which was trying to use them. The order was random - if the first used object happened to be EvaluationLogic, then the error emerged. It the first object happened to be PhaseLogic, everything was fine.
Now, when you have a file for the module itself, and define constants in that file (app/models/logic.rb), autoloading will be able to find and execute the definitions before any class starts to use them. I hope everything will be OK.
I am implementing an API in Rails 3, and noticed an example controller defined like class Api::ToursController < ApplicationController. Does anyone know what the to colons indicate? Is it inheritance? Or is it indicating extending the ToursController? I have tried searching for an answer, but have not come up with anything.
Here is what I am referencing: https://github.com/nesquena/rabl/wiki/Set-up-rabl-for-Ruby-on-Rails
:: is the scope resolution operator (i.e. namespace operator) in many languages, including C++ and Ruby, so it's not specific to Rails.
In Ruby, modules define namespaces, so you can see code like this:
Net::HTTP.get 'stackoverflow.com'
Which calls the get class method on the HTTP class in the Net module.
In Rails, namespaces allow you to better organize your code (e.g. to separate your API controllers from the rest), and are implemented as modules.
Api::ToursController indicates that there is an outer Module called Api , in which the ToursController class is located. :: is the namespace operator.
Sometimes you see a module name preceded with :: , e.g. ::Something , this indicates to Ruby to look in the outer-most namespace (Main) for the Class or Module called Something. This typically happens when you're somewhere in the source code of a gem and it references an outer Class or Module.
You can do include Api to include everything in the Module Api at the current level, this way you don't need the namespace operator, and can use ToursController without prefixing it with 'Api::'
It's namespace! Module::Class.method
I have a piece of code that is needed in 2 of my controllers, but not all of them. Where does this method belong?
I have read about helpers, but those seem to be for view-related code. Someone proposed the lib-folder, but that seems 'too far away' from the controller logic, i don't need it in views or models.
Has someone experience with that sort of problem?
There are three options, the easiest (though, the most unclean) is the application controller. The other two options are a shared parent controller
class FooController < FooBarParentController
# code here
end
class BarController < FooBarParentController
# code here
end
Usage depends on how related these controllers are.
The final solution is a module
module FooBarModule
extend ActiveSupport::Concern
included do
# class level code
# before_filter ....
end
module ClassMethods
# all class methods here
end
# instance methods here
end
This is where the shared code required is for a handful of ad-hoc controllers, or if you are already using the inheritance above and this code doesn't quite fit into this subset (thus attempting to emulate multiple inheritance).
I am using Ruby on Rails 3 and I would like to move some custom and shared code in a module.
What syntax should I use to write the module code?
In which folder of my application I have to place the module file?
How I have to include that module in one or more controller classes?
What other action, if any, do I have to use the custom module anywhere in my application?
How can I call methods in the module from my application?
To 1. A module is created/opened
by simply saying:
module MyModule
def first_module_method
end
end
To 2. The lib folder. If you want to organize your modules in the lib folder, you can put them into modules themselves. For example, if you wanted a subfolder super_modules your modules would be defined as follows:
module SuperModules
module MyModule
def first_module_method
end
end
end
To 3./5. When including the module in a class you can simply call the modules methods as if they were defined within the class:
class MyClass
include MyModule
def some_method
first_module_method #calls module method
end
end
To 4.
Frst, make sure that your module is really needed in every class of your application. If it isn't it makes sense to only include it where it is need so as not to bloat the classes that don't need it anyways. If you really want the module everywhere, include look at the class hierarchy of your classes in the app. Do you want the module in all models? You could open ActiveRecord::Base and add add your module there.
A>1. You can use the same syntax as any other ruby class. For instance, I'm defining a VehicleClassifer module which is going to use the classify_vehicle method to classify a vehicle based on the number of wheels it receives as an input.
module VehicleClassifer
def classify_vehicle(number_of_wheels)
VehicleType.where("number_of_wheels = ?", number_of_wheels)
end
end
A>2. Modules are usually stored in the /lib folder.
questions 3,4,5 have more or less the same answer. you can use
class SomeController < ApplicationController
include VehicleClassfier
def index
classify_vehicle(4)
end
end
in the class you're using the module and you will have access to all the module's methods.
Also, In case you need to use a module through out your app, you can include it in your application controller.