In Rails, how do you use a specific method from a module. For eg,
# ./app/controllers/my_controller.rb
class MyController < ApplicationController
include MyModule
def action
MyModule.a_method
end
private
def a_method
...
end
end
# ------------------------------------------------ #
# ./app/helpers/my_module.rb
module MyModule
def a_method
...
end
end
MyController includes MyModule. And in action ,I want to use MyModule.a_method (Please note I also have a private a_method in MyController and I don't want to use this.)
Things I've tried :
1) Defining the method in the module as self.
def self.a_method
end
2) Using the :: notation in controller (MyModule::a_method)
The error that I keep getting is
Undefined method:a_method for MyModule:module
For now, I've resorted to using a different name for the modules method. But I'd like to know how to namespace the function with either the Module:: or Module. notation
[UPDATE - 11/24/2014]
adding file structure in code, since Rails heavily relies on convention.
So I am not really sure what you are trying to accomplish with your module but a quick solution to get it working is below.
Move my_module.rb out of helpers and into lib/my_module.rb. The helpers directory is for methods that you use in your views. The convention is to utilize helpers that are namespaced after their respective controller or the application_helper.rb for global methods for your views. Not sure if that's what you are trying to accomplish with your module but wanted to throw that out there.
Create an initializer (you can all it whatever) in config/initializers/custom_modules.rb and add require 'my_module'
Update the a_method back to be self.a_method
You can now call MyModule.a_method in your app
Don't forget to restart your server for changes to lib/my_module.rb to take effect.
Also, a lot of people reference this post by Yehuda Katz as guidance on where to store code for your app. Thought it might be a helpful reference.
if you include MyModule into MyController, all the "instance methods" of the first will be mixed-in into the 2nd.
So if you only want to call MyModule.a_method, no need to include your module.
Then you'd want to require (or better autoload) your module before using it. To do so place it in controllers/concerns/my_module.rb, rails (4 at least) should autoload it, otherwise require its file in an intializer
# my_module.rb
module MyModule
def self.a_method
...
end
end
should work, but doing
# my_module.rb
module MyModule
extend self
def a_method
...
end
end
is more clean to me. You'd like to have a look to rails active support concern to understand the "rails way" on this topic.
Related
I am stuck in a weird Design problem,
I'm facing issues when I'm trying to invoke a application helper method in another helper which have multiple class and want to access application helper method.
what is the better approach?
Thoughts about what can I do?
my code looks similar like this,
## app/helpers/application_helper.rb
module ApplicationHelper
def my_name
"stackoverflow"
end
end
Another helper with sub classes
## app/helpers/my_helper.rb
module MyHelper
class MyTestclass
def want_myname
my_name ## giving undefined method-- how can i call myname method here?
end
end
end
undefined method `myname' for MyHelper::MyTestclass
Here is a brief explanation of your problem and how to use modules:
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.
Does anybody know why the included method doesn't work inside a class method?
class MyClass
include ActionView::Helpers::NumberHelper
def test
puts "Uploading #{number_to_human_size 123}"
end
def self.test
puts "Uploading #{number_to_human_size 123}"
end
end
ree-1.8.7-2011.03 :004 > MyClass.new.test
Uploading 123 Bytes
=> nil
ree-1.8.7-2011.03 :005 > MyClass.test
NoMethodError: undefined method `number_to_human_size' for MyClass:Class
from /path/to/my/code.rb:9:in `test'
from (irb):5
ree-1.8.7-2011.03 :006 >
For anyone wanting to use some custom helpers in class level lib or model, sometimes it is not worth it to include all helpers. Instead, call it directly:
class MyClass
def test
::ApplicationController.helpers.number_to_human_size(42)
end
end
(Taken from http://makandracards.com/makandra/1307-how-to-use-helper-methods-inside-a-model)
It's hard to tell without seeing your helper code, but include will insert all of the methods in that module into instances of the class you include into. extend is used to bring methods into a class. Therefore, if you just have methods defined in NumberHelper, these are being put onto all instances, but not the class, of MyClass.
The way that lots of Rails extensions work is using techniques that have been consolidated into ActiveSupport::Concern. Here is a good overview.
Essentially, extending ActiveSupport::Concern in your modules will allow you to specify, in sub-modules called ClassMethods and InstanceMethods, what functions you want to be added to classes and instances into which you include your module. For example:
module Foo
extend ActiveSupport::Concern
module ClassMethods
def bar
puts "I'm a Bar!"
end
end
module InstanceMethods
def baz
puts "I'm a Baz!"
end
end
end
class Quox
include Foo
end
Quox.bar
=> "I'm a Bar"
Quox.new.baz
=> "I'm a Baz"
I've used this before to do things like define the bar function in ClassMethods, then also make it available to instances by defining a bar method of the same name that just calls this.class.bar, making it callable from both. There are lots of other helpful things that ActiveSupport::Concern does, like allowing you to define blocks that are called back when the module is included.
Now, this is happening here specifically because you're includeing your helper, which might indicate that this functionality is more general-purpose than a helper - helpers are only automatically included in views, since they are only intended to help with views. If you want to use your helper in a view, you could use the helper_method macro in your class to make that method visible to your views, or, even better, make a module as above and not think about it as a helper, but use include to mix it in to the classes you want to use it in. I think I would go that route - there's nothing that says you can't make a HumanReadableNumber module and include it in NumberHelper to make it easily available across your views.
I faced the same issue. Here's how I solved it,
helper = Object.new.extend(ActionView::Helpers::NumberHelper)
helper.number_to_human_size(1000000)
Thanks to RailsForum.
I was facing the same problem. in my case, replacing the include with extend made it work.
class MyClass
extend ActionView::Helpers::NumberHelper
...
end
Ok so I am using some module/lib/plugin (not sure of the exact name), let's say its a authentication/authorization plugin like: http://github.com/technoweenie/restful-authentication
class HomeController < ApplicationController
some_module_name_here
end
Now just from adding the code above 'some_module_name_here', I can access to methods from that module.
What is that line of code doing that gives me access to methods/objects from the module?
Is that declaring a variable like in say java/c#:
public SomeModule _someModule;
I know that plugins/modules basically extend the class under the covers, but how does it do this with a single line of code?
Is it called in the constructor somehow?
When you create a ruby plugin, and load it into the rails app via environment.rb, bundler, or a require call, the methods are loaded as "modules" that can be called. The ones that act like you're talking about will have an extra method called acts_as_list or something similar. All that method does is include the methods of the module into the class where that line was called.
Here's an example, which you could include in your app's lib folder and play with:
module Bellmyer
module Pointless
def self.included(base)
base.extend PointlessMethods
end
module PointlessMethods
def acts_as_pointless
unless included_modules.include? InstanceMethods
extend ClassMethods
include InstanceMethods
end
end
end
module ClassMethods
def pointless_class?
true
end
end
module InstanceMethods
def pointless_instance?
true
end
end
end
end
The module is available to any ruby class in your app, but the methods don't actually get loaded until you call acts_as_pointless, which then includes and extends your class with the methods listed. Only the acts_as_pointless method is immediately available to the model. This is the standard pattern for an ActiveRecord plugin.
That's not how it works.
When the plugin or gem is loaded it adds a class method to, in this case, ApplicationController named some_module_name. When you call that methods, a bunch of other class and instance methods are included.
Check out your favourite gem or plugin to see how they do it exactly.
I am upgrading my Rails plugin to be an engine that works with the latest 3.0RC1 release and I'm having a bit of trouble figuring out the best (and most correct) way to extend ActionController. I've seen this post by DHH and this question here on SO, but my question is more about how to properly call code within the ActionController.
For instance, I need to call the following within my engine's controller:
class ApplicationController < ActionController::Base
helper :all
before_filter :require_one_user
after_filter :store_location
private
def require_one_user
# Code goes here
end
def store_location
# Code goes here
end
end
I know how to properly include my two private functions, but I can't find a way to get it to properly call helper, before_filter and after_filter.
I would greatly appreciate some links or a way to make this work. I have tried naming my controller something other than ApplicationController and having the real ApplicationController extend it, but that doesn't seem to work either. I'm really up for any solution that makes the life of the engine user as easy as possible. Ideally, they wouldn't have to extend my class, but they'd have all of the functionality built into their own ApplicationController.
You may also want to look into the initializers inside your engine subclass, so you don't have to include view helpers inside your controller class. And this will give you control over the load order of these modules.
Here is what I have been using:
module MyEngine
class Engine < Rails::Engine
initializer 'my_engine.helper' do |app|
ActionView::Base.send :include, MyEngineHelper
end
initializer 'my_engine.controller' do |app|
ActiveSupport.on_load(:action_controller) do
include MyEngineActionControllerExtension
end
end
end
end
Also, another option for the action controller extension is using a mixin module. This will let you use the before_filter, after_filter, etc..
module MyEngineActionControllerExtension
def self.included(base)
base.send(:include, InstanceMethods)
base.before_filter :my_method_1
base.after_filter :my_method_2
end
module InstanceMethods
#...........
end
end
One other thing... if you create the default rails directories at the top level of your gem, you don't have to worry about requiring the helpers or controllers. Your engine subclass has access to them. So I add my application controller and application helper extensions here:
/myengine/app/helpers/myengine_application_helper_extension.rb
/myengine/app/controllers/my_engine_action_controller_extension.rb
I like this setup because it looks similar to the application_controller and application_helper in your rails app. Again, this is just personal preference, but I try to keep anything that is directly rails related, such as controllers, helpers and models inside /my_engine/app and anything that is related to the plugin in general inside /my_engine/lib
Check out this tutorial by Jose Valim for more info on initializers:
https://gist.github.com/e139fa787aa882c0aa9c (engine_name is deprecated now, but most of this doc seems up-to-date)
So, I finally figured out the solution and I hope it helps someone else.
You need to create a file in your lib directory because you are actually going to extend the class. I did myplugin/lib/extensions/action_controller_base.rb.
Then, inside of your myplugin/lib/myplugin.rb file, do the following:
require 'extensions/action_controller_base.rb'
Inside of myplugin/lib/extensions/action_controller_base.rb put the following:
require 'action_controller' # Make sure ActionController::Base is defined
ActionController::Base.class_eval {
private
def my_method_1
# Code Goes Here
end
def my_method_2
# Code Goes Here
end
}
ActionController::Base.instance_eval {
helper_method :my_method_1, :my_method_2
before_filter :my_method_1
after_filter :my_method_2
}
If you need to have view helpers, create them in the myplugin/lib/helpers directory (or anything inside of lib, the name "helpers" doesn't matter) also and add the following to the bottom of myplugin/lib/extensions/action_controller_base.rb:
require 'helpers/helper_file_1'
require 'helpers/helper_file_2'
ActionView::Base.send :include, MyHelper1
ActionView::Base.send :include, MyHelper2
I'm writing a Rails plugin (lets call it Foo).
I want it to provide 'bar' class function in controllers, so that I can do:
class ApplicationController
bar ...
end
bar is defined from withing the plugin loading file vendor/plugins/foo/init.rb. Something like
class ActionController::Base
def self.bar
...
end
end
The problem is that some other plugins (in my case ResourceController) might load before foo and access ApplicationController.
So what happens is that ApplicationController is loaded before the plugin 'foo' and fails since there is no 'bar' defined YET.
So ... how do I properly make it work works?
I noticed that many other plugins that extend ActionController (for example inherited_resources, resource_controller, ) are doing exactly the same, so it seems its a matter of who loads first to decide if it fails or works.
I know that I can put code in some module and manually add the module to ApplicationController code before calling 'foo'. I'd rather not, I like the cleanliness of just 'foo'.
I also don't want to do a manual 'require'. Plugins are supposed to be auto-loaded all by themselves :)
What you have is a classic plugin load order problem. Ryan Daigle had a nice article on this back in 2007. I'll sum up the recommendation here:
# in RAILS_ROOT/config/environment.rb:
...
Rails::Initializer.run do |config|
# load Bar before Foo, then everything else:
config.plugins = [ :bar, :foo, :all ]
...
end
From what I understand,
ResourceController loads before plugin foo and tries to use the bar method you have defined in foo.
Usually, gems and plugins are loaded before application classes. (Take a look at rails/railties/lib/initializer.rb). Could you provide a stack-trace of the error so that one can debug this.
Also, for extending the classes, this seems a better alternative to me:
module ActionController
class Base
class << self
... # Class methods here
end
... # Instance methods here
end
end