Can I include helper method in service object? - ruby-on-rails

I defined a helper method: MembersHelper
module MembersHelper
def current_segment
Segment.where(current: true).first
end
end
then included it in a class call Base in app/service/enum_data/base.rb file
module EnumData
class Base
include MembersHelper
end
end
And used it from Base's subclass: GetAll in app/service/enum_data/get_all.rb file
module EnumData
class GetAll < Base
def self.call
reference_data = current_segment.entities.all
end
end
end
But I got an error
undefined local variable or method 'current_segment' for EnumData::GetByCategory:Class
I fixed it by moving current_segment method to Base class, but I want to know why it doesn't work when I include that helper method? Did I miss something?

You are using include, which makes current_segment an instance method in the including classes while what you need, is a class instance method (singleton method). In order to achieve it you should use extend:
module EnumData
class Base
extend MembersHelper
end
end

Related

Loading module into User Model in Rails

Trying to make available the methods I have stored in a Module which is located in app/models (side note: not sure if this is the correct place for modules?).
Module:
module MyModule
class MyClass
def some_method
# do something
end
end
end
User Model:
class User < ApplicationRecord
include MyModule
def another_method
some_method
end
end
I am getting a NoMethodError:
NoMethodError (undefined method 'some_method' for #<User:0x00007f6a3ce452c0>
You seem to have missunderstood what what modules and classes do in Ruby. In Ruby a module is simply an object that wraps a set of methods and constants.
A module can extend other modules, classes and objects and can be included in classes thus implementing multiple inheritance. Modules in Ruby fill the role that traits, namespaces and singletons do in other languages.
Classes are actually modules (Module is part of the ancestors chain of Class) with the key difference that you can make instances of a class and that class can inherit from a single other class and cannot extend other objects or be included.
The code example here actually doesn't make sense. If you want to declare a method that will be available to classes that include a module you want to declare it in the module itself:
module MyModule
def some_method
# do something
end
end
When you then call User#another_method it will look in the ancestors chain of the User class until it finds the method which is defined in MyModule.
module MyModule
class MyClass
def some_method
# do something
end
end
end
Will actually definte the class MyClass with an instance method that is only available to instances of MyClass. The only thing that the module does here is change the module nesting so that the class is defined in MyModule instead of the global namespace.
If you want to mix in a method from a method into your class then just put the methods directly in the module (without an intermediate class).
Module:
module MyModule
def some_method
# do something
end
end
User Model:
class User < ApplicationRecord
include MyModule
def another_method
some_method
end
end
Have a look at this answer, you need to instantiate your Class first. Or if you want to
class User < ApplicationRecord
include MyModule
def another_method
my_instance = MyClass.new
my_instance.some_method
end
end
As for a place to store your Module, have a look at this guide about service objects, it gave me some inspiration when it comes to different modules.

How to correctly use controllers helper modules in Rails, and how to connect between those helpers?

I'm trying to call a method in one controller helper (a module) from another controller helper. It seems to be not possible, even if that method is under the module_function.
I guess I'm missing a fundamental principle in Ruby since I'm pretty newbie. Also it feels like I'm missing the point of how to write right OOP under Rails.
Update: here is an example:
I have FirstController and SecondController, and helper module for each
module FirstHelper
module_function
def methodA
...
end
end
module SecondHelper
def methodB
FirstHelper.methodA
end
end
The call for FirstHelper.methodA from SecondHelper is returning an error:
undefined method `methodA' for SecondHelper:Module
A module is a collection of methods and constants. It basically provides a namespace and prevents name clashes. You need to include or extend your First module inside your Second module.
Include is for adding methods to an instance of a class and Extend is for adding class methods. Read this for more information or this. In your case you can do something like this:
module FirstHelper
def self.methodA
...
end
end
module SecondHelper
include FirstHelper
def methodB
FirstHelper.methodA
end
end
Helper methods are instance methods and cannot be accessed via module, but only vie classes they are included in. All the helpers are included within the view context object, so you should be able to access them simply by name:
module SecondHelper
def methodB
methodA
end
end
use require instead of include it will work
module FirstHelper
class << self
def methodA
...
end
end
end
require 'lib/first_helper'
module SecondHelper
def methodB
FirstHelper.methodA
end
end

Using methods defined in a module with class methods in Ruby

I have a small problem that I can't quite get my head around. Since I want to reuse a lot of the methods defined in my Class i decided to put them into an Helper, which I can easily include whenever needed. The basic Class looks like this:
class MyClass
include Helper::MyHelper
def self.do_something input
helper_method(input)
end
end
And here is the Helper:
module Helper
module MyHelper
def helper_method input
input.titleize
end
end
end
Right now I can't call "helper_method" from my Class because of what I think is a scope issue? What am I doing wrong?
I guess that is because self pointer inside of do_something input is InternshipInputFormatter, and not the instance of InternshipInputFormatter. so proper alias to call helper_method(input) will be self.helper_method(input), however you have included the Helper::MyHelper into the InternshipInputFormatter class as an instance methods, not a singleton, so try to extend the class with the instance methods of the module as the signelton methods for the class:
class InternshipInputFormatter
extend Helper::MyHelper
def self.do_something input
helper_method(input)
end
end
InternshipInputFormatter.do_something 1
# NoMethodError: undefined method `titleize' for 1:Fixnum
As you can see, the call has stopped the execution inside the helper_method. Please refer to the document to see the detailed difference between include, and extend.

Calling one module method from another of the shared same class

I have this class:
class SpecialAwesome
module Controller
def builder
SpecialAwesome.with_member(current_member)
which fails saying:
NoMethodError: undefined method `with_member'
But then I see the method here at:
class SpecialAwesome
module Options
def with_member member
self.class.new options.merge(:member => member)
end
How come the other file doesn't recognize this method?
The with_member method is defined as an instance method on SpecialAwesome::Options, not as a class method of SpecialAwesome. Probably, this is an issue.
with_member is not SpecialAwesome class method, but it is defined in Options module. To make it work as you expect, you can for example use extend method:
class SpecialAwesome
module Options
# ...
end
extend Options
# ...
end
which will add methods defined in Options module as SpecialAwesome class methods.

rails 3: in a Class method self.do_something() how do I access an ApplicationHelper method?

My model, Widget.rb, has include ApplicationHelper and my instance methods have no trouble using any method defined in application_helper.rb
However, when I try to use one of the helper methods in any of my class methods such as
def self.send_broadcast(guid)
track_guids(guid) # defined in application_helper.rb
end
I get No Method error.
Is there some secret handshake to permit use of a ApplicationHelper method inside a class method?
ApplicationHelper is just a module:
module ApplicationHelper
def track_guids(something)
end
end
class Widget
extend ApplicationHelper
def self.send_broadcast(guid)
track_guids(guid)
end
end
Now you should have access to the module methods from a class method. I'm not sure if you can both extend and include the same module though... not really sure what that'd do.
Edit to add:
I'm not sure what will happen if you try both extending and including the same module into the class. With extend you get the module included at the class-level, with include it is included at the instance-level. It might give you the methods at both class and instance if you do both... or it might die horribly. Give it a try?
I don't think you can access instance methods unless self is an instance. You could make an instance of Widget and call a class method from that, or you could try to call the methods from the module directly.

Resources