How can I include the module with class to another class? - ruby-on-rails

I have module with class
module My < Grape::API
prefix 'api'
format :json
class Users
helpers do
include My2 #I want put here method 'some_method'
end
end
end
I have another module
module My2
class Circle
def some_method
"Hello"
end
end
end
I can do this, but I wonder how to do with the class
module My2
def some_method
"Hello"
end
end
I don't understand logical .. Thank you
How can I do it another way?

You can't use include for including a class, because it uses for including methods from modules in classes.
If you want to use a class, try to pass an instance of class or create class's method.
class Foo
def self.bar
puts 'class method'
end
def baz
puts 'instance method'
end
end
Foo.bar # => "class method"
Foo.baz # => NoMethodError: undefined method ‘baz’ for Foo:Class
Foo.new.baz # => instance method
Foo.new.bar # => NoMethodError: undefined method ‘bar’ for #<Foo:0x1e120>
Example

I can put
def some_method(x, y)
My2::Circle.new.some_method(x, y)
end

Related

Can't access to attr_accessor in Concern Ruby on Rails

I want to register the class method in concern and access to attr_accessor, but it doesn't work. This is my sample code. Please help me how can I do this. Thank you so much!
app/controllers/concerns/foobar_concern.rb
module FoobarConcern
extend ActiveSupport::Concern
included do
class << self
attr_accessor :foo
end
end
class_methods do
def test_method(bar)
self.foo = bar
end
end
end
app/controllers/foobar_controller.rb
class FoobarController < ApplicationController
include FoobarConcern
test_method 'Just test'
def index
self.foo => NoMethodError: undefined method "foo"
foo => NameError: undefined local variable or method "foo"
end
end
Just delegate required methods to the class like this
module FoobarConcern
extend ActiveSupport::Concern
included do
delegate :foo, :foo=, to: :class
class << self
attr_accessor :foo
end
end
end
The issue is that you're defining a method at the class level (FoobarController.foo) but calling it on an instance of the class (FoobarController.new.foo).
One option is to call the foo method on the class instead:
def index
self.class.foo
end
You can also define an accessor method for instances of the class like:
module FoobarConcern
extend ActiveSupport::Concern
included do
class << self
attr_accessor :foo
end
end
class_methods do
def test_method(bar)
self.foo = bar
end
end
# -- NEW ---
# This `foo` method is defined for instances of the class and calls the class method.
def foo
self.class.foo
end
end

Is there a way to use class method in a module without extend it in rails?

currently I have a module like this:
module MyModule
def A
end
.....
end
and I have a model that I want to use that method A as a class method. However, the thing is I only need that A method. If I extend it, I am gonna extend the other unnecessary class methods into my model. Therefore, is there a way for me to do sth like MyModule.A without rewriting the module like this:
module MyModule
def A
...
end
def self.A
...
end
.....
end
It is kind of repeating myself if I do it that way. I still feel there is a better way to do it in Rails.
Use Module#module_function to make a single function to be a module function:
module M
def m1; puts "m1"; end
def m2; puts "m2"; end
module_function :m2
end
or:
module M
def m1; puts "m1"; end
module_function # from now on all functions are defined as module_functions
def m2; puts "m2"; end
end
M.m1 #⇒ NoMethodError: undefined method `m1' for M:Module
M.m2 #⇒ "m2"
Yes, you can define it as a module_function, then you should be able to access it using module name.
Ex:
module Mod
def my_method
100
end
def self.my_method_1
200
end
module_function :my_method
end
Mod.my_method
# => 100
Mod.my_method_1
# => 200
Note: No need to add the self defined methods in module_function, they are accessible directly. But it's needed for methods defined without self

Access a Ruby module's method within same module

I'm new to Ruby and probably don't understand something basic:
I'm trying this:
# lib/common_stuff.rb
module CommonStuff
def self.common_thing
# code
#x = second_thing # --> should access method in same module. Doesn't work.
end
def self.second_thing
# code
end
end
# app/controllers/my_controller.rb
require 'common_stuff'
class MyController < ApplicationController
include CommonStuff
y = self.common_thing # accesses the Module method -> works
end
Error:
NoMethodError (undefined method `second_thing' for
MyController:0x000000088d8990): lib/common.rb:7:in 'common_thing'
I tried both with Module and instance methods. Also declaring only the second_thing an instance method or both methods in the Module as instance methods doesn't work. What do I misunderstand?
** EDIT Corrections**
I realized that my mistake was to make the methods class methods (with self. prefix). Without that it actually works. Thought I tried that, but I must have been blind yesterday. So the working code is (just a constructed example - normally I wouldn't instantiate the controller of course):
# lib/common_stuff.rb
module CommonStuff
def common_thing
#x = second_thing # --> access method in same module. Works now too.
end
def second_thing
10
end
end
# app/controllers/my_controller.rb
require 'common_stuff.rb'
class MyController
include CommonStuff
def a_class
y = common_thing # accesses the Module method -> works
puts y
end
end
ctrl = MyController.new
ctrl.a_class
What do I misunderstand?
1) An #variable is private, so you always need to provide an accessor method to access it (or use instance_variable_get() to violate privacy):
module CommonStuff
def common_thing
#x = second_thing # --> should access method in same module. Doesn't work.
end
def second_thing
10
end
end
class MyController
include CommonStuff
attr_accessor :x
end
obj = MyController.new
obj.common_thing
puts obj.x
--output:--
10
2) You can't include a module's class methods:
module CommonStuff
def self.common_thing
puts 'hello'
#x = second_thing # --> should access method in same module. Doesn't work.
end
def self.second_thing
10
end
end
class MyController
include CommonStuff
end
CommonStuff.common_thing
MyController.common_thing
--output:--
hello
1.rb:21:in `<main>': undefined method `common_thing' for MyController:Class (NoMethodError)
#obj = MyController.new
#obj.common_thing #Same error here
If you want to inject some class methods into MyController, you need to rework your CommonStuff module:
module CommonStuff
def self.included(includer) #Advanced 'hook' method
includer.extend ClassMethods
end
module ClassMethods
def common_thing
puts 'hello'
#x = second_thing # --> should access method in same module. Doesn't work.
end
def second_thing
10
end
end
end
class MyController
include CommonStuff
y = common_thing
puts y
puts instance_variable_get(:#x)
end
--output:--
10
10
The hook method is called whenever the module is included by another class/module, and the method is passed the including class/module as an argument.
Response to commment:
Only a controller's instance variables are made available in a view, e.g.:
class MyController
def do_stuff
#x = 10 #instance variable
end
end
but #variables created inside class methods are not the controller's instance variables:
class MyController
def self.do_stuff
#x = 10
end
end
Therefore, #variables created inside class methods will not be available in the view.

Run a helper method on a model class method

I created a helper method that I want to run on a model class method and getting a method not found error.
lib/model_helper
module ModelHelper
def method_i_want_to_use
puts "I want to use this method"
end
end
model/foo
class Foo < ActiveRecord::Base
include ModelHelper
def self.bar
method_i_want_to_use
end
end
This setup gives me a no method error.
You have to extend the module instead of include.
extend ModelHelper
include makes the methods available as instance methods of Foo. That means, you can call the method method_i_want_to_use on instances of Foo, not on Foo itself. If you want to call on Foo itself, then use extend.
module ModelHelper
def method_i_want_to_use
puts "I want to use this method"
end
end
class Foo
extend ModelHelper
def self.bar
method_i_want_to_use
end
end
Foo.bar
# >> I want to use this method

How to alias a class method within a module?

I am using Ruby v1.9.2 and the Ruby on Rails v3.2.2 gem. I had the following module
module MyModule
extend ActiveSupport::Concern
included do
def self.my_method(arg1, arg2)
...
end
end
end
and I wanted to alias the class method my_method. So, I stated the following (not working) code:
module MyModule
extend ActiveSupport::Concern
included do
def self.my_method(arg1, arg2)
...
end
# Note: the following code doesn't work (it raises "NameError: undefined
# local variable or method `new_name' for #<Class:0x00000101412b00>").
def self.alias_class_method(new_name, old_name)
class << self
alias_method new_name, old_name
end
end
alias_class_method :my_new_method, :my_method
end
end
In other words, I thought to extend the Module class someway in order to add an alias_class_method method available throughout MyModule. However, I would like to make it to work and to be available in all my Ruby on Rails application.
Where I should put the file related to the Ruby core extension of the Module class? Maybe in the Ruby on Rails lib directory?
How should I properly "extend" the Module class in the core extension file?
Is it the right way to proceed? That is, for example, should I "extend" another class (Object, BasicObject, Kernel, ...) rather than Module? or, should I avoid implementing the mentioned core extension at all?
But, more important, is there a Ruby feature that makes what I am trying to accomplish so that I don't have to extend its classes?
You could use define_singleton_method to wrap your old method under a new name, like so:
module MyModule
def alias_class_method(new_name, old_name)
define_singleton_method(new_name) { old_name }
end
end
class MyClass
def my_method
puts "my method"
end
end
MyClass.extend(MyModule)
MyClass.alias_class_method(:my_new_method, :my_method)
MyClass.my_new_method # => "my method"
Answering your comment, you wouldn't have to extend every single class by hand. The define_singleton_method is implemented in the Object class. So you could simply extend the Object class, so every class should have the method available...
Object.extend(MyModule)
Put this in an initializer in your Rails app and you should be good to go...
I found an answer on this website: http://engineering.lonelyplanet.com/2012/12/09/monitoring-our-applications-ruby-methods/
The solution is to use class_eval with a block. That enables using variables from the enclosing scope.
module Alias
def trigger
#trigger = true
end
def method_added(name)
if #trigger
#trigger = false
with_x = "#{name}_with_x"
without_x = "#{name}_without_x"
define_method(with_x) do
"#{send(without_x)} with x"
end
alias_method without_x, name
alias_method name, with_x
end
end
def singleton_method_added(name)
if #trigger
#trigger = false
with_x = "#{name}_with_x"
without_x = "#{name}_without_x"
define_singleton_method(with_x) do
"singleton #{send(without_x)} with x"
end
singleton_class.class_eval do
alias_method without_x, name
alias_method name, with_x
end
end
end
end
class TestAlias
extend Alias
trigger
def self.foo
'foo'
end
trigger
def bar
'bar'
end
end
TestAlias.foo # => 'singleton foo with x'
TestAlias.new.bar # => 'bar with x'
If you don't have singleton_class then you should probably upgrade your version of Ruby. If that's not possible you can do this:
class Object
def singleton_class
class << self
self
end
end
end
The accepted answer was confusing and did not work.
class Module
def alias_class_method(new_name, old_name)
define_singleton_method(new_name, singleton_method(old_name))
end
end
module MyModule
def self.my_method
'my method'
end
end
MyModule.alias_class_method(:my_new_method, :my_method)
MyModule.my_new_method # => "my_method"

Resources