I have a method defined in application_helper.rb:
def bayarea_cities
[
['San Francisco', 'San Francisco'],
['Berkeley', 'Berkeley'],
...
]
end
I'm also using Grape to create an API. It's in its own module outside the Rails app:
module FFREST
class API_V2 < Grape::API
...
I'm pretty sure Grape is a Rack app, so it doesn't have normal access to the Rails modules. When I try to call the 'bayarea_cities' method in one of the API methods, I get an undefined variable or method error. I've tried include the ApplicationHelper module with 'include ApplicationHelper', but this did not work.
How can I get access to this inside the API class?
UPDATE:
Thanks for the update Deefour. I added extend self to my Helpers module, and referenced the methods as instance/mixin methods (not as module methods), but I'm still getting the same error. In my lib/helpers.rb file I have:
module Helpers
extend self
def bayarea_cities
[
'San Francisco',
'Berkeley',
'Danville',
'Oakland',
'Daly City',
'Sunnyvale'
]
end
def us_states
['CA']
end
end
and in my API file I have:
module FFREST
class API_V1 < Grape::API
include Helpers
version 'v1', :using => :header, :vendor => 'feedingforward'
...
And of course, I have the config/initializers/helpers.rb file that says require "helpers"
But when I call the US states API method, for instance, by going to http://localhost:5000/api/states, I get:
undefined local variable or method `us_states' for #<Grape::Endpoint:0x007fd9d1ccf008>
Any ideas?
Create some lib/helpers.rb file with the contents: module Helpers; end
Move the bayarea_cities method into this module definition
Add a config/initializers/helpers.rb file containing require "helpers"
Inside the ApplicationHelpers class, add include Helpers
Inside your API_V2 class add include Helpers
You'll now have told Rails to make the Helpers module available within your application, and made bayarea_cities available as a method within both your Grape API class and your Rails app. The above are steps simply to get the point across - you need to put this common functionality in a place it can be easily accessed by any part of your application. You can (and should) use namespace your Helpers module.
Another tip: add extend self to the module to avoid the need to define everything as class methods as you mentioned in the comment
module Helpers
extend self
def bayarea_cities
#...
end
end
Finally, if you're including the module properly with include Helpers, you should be able to acces the method simply as bayarea_cities, not Helpers.bayarea_cities. If this isn't the case, you should definitely show the error you get so we can sort that out for you.
Related
I've generated an object via a ruby gem (Koala) and I've written a few modules with helper methods. What do I need to do in order to be able to use the methods within the modules on the object?
If I, model_object = Model.new, model_object will have access to all the instance variables but object does not (see below).
Ruby 2.1, Rails 4.1
config/application.rb - Autoloading modules in folder
config.autoload_paths << Rails.root.join('lib/module_folder')
Model
class Model < ActiveRecord::Base
include Module
include Module::Module2
include Module::Module3
def self.create_account(token)
object = Module.module_class_method(token) #this works and generates the Koala object
ERROR: object.module2_instance_method # Error: NoMethodError Exception: undefined method
end
end
Module
module Module
extend ActiveSupport::Concern
end
Module2
module Module
module Module2
def module2_instance_method
end
end
end
SOLVED MYSELF
- the issue was the include statements being within the class, if I moved them outside it worked.
I believe if you include your modules somewhere under the app/ directory - they will be included automatically. Otherwise, you actually have to require them in your rails code explicitly with a require statement
Without seeing the actual code, I think the problem with Module2 in your code snippet is the self. method.
Because you are calling module2_instance_method on an instance of your object, the method in the module cannot have the self. because that designates a class method and, as such, would have to be called as Module::Module2.module2_instance_but_not_really_because_I_am_a_class_method.
I believe if you change def self.module2_instance_method ... end to def module2_instance_method ... end, you should no longer receive the NoMethodError exception.
Apologies if I've misread or misunderstand the OP.
Moved the include statements from inside to above the class declaration and all methods began to work. My assumption is that when they are within the statement they are only available to objects of that class.
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.
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.
I have a module called Sms that I'm defining in lib/sms.rb. Within it, I have a method called Sms.chunk that uses the method word_wrap. This is part of the TextHelper library, so I am including it at the beginning of the module with include ActionView::Helpers::TextHelper:
module Sms
include ActionView::Helpers::TextHelper
def Sms.chunk
...
word_wrap
...
I am requiring this module during initialization with the line require "sms" in config/initializers/additional_libs.rb
I also have a Grape API class called TWILIO_API where I want to call Sms.chunk. However, when I do, I get undefined methodword_wrap' for Sms:Module`. I have tried including the TextHelper library in the TWILIO_API class itself, and various other ways of including it, but have had no success.
What am I doing wrong here?
The problem is that wrap_word is an instance method , and you're invoking it from a class method Sms.chunk. Make it an instance method by dropping the Sms. part. For instance, the following works:
require 'action_view'
class Test
include ActionView::Helpers::TextHelper
def test_method
word_wrap('Once upon a time')
end
end
o = Test.new
p o.test_method # "Once upon a time"
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.