Module level method and a Class within same module in Ruby - ruby-on-rails

I have the similar module in my Rails application
module Demo
def self.create
puts 'inside module method'
AnotherTestClass.new('testing')
end
class ModuleClass
def initialize(test)
#test = test
puts "inside class #{#test}"
end
end
end
module Demo
class AnotherTestClass < ModuleClass
end
end
So when I call Demo.create in my Controller, I am getting the following error
undefined method `create' for Demo:Module
Note: When I execute this code in irb, it works.

Related

Error with Namespace Ruby

I'm experimenting with some Ruby code in a Ruby on Rails project and trying to code a nested namespace with inheritance.
In app/messages/message.rb I have the following code:
module Messages
class Message
def initialize
puts "message constructor"
end
end
end
In app/messages/emails/email.rb I have this code:
module Emails
class Email < Messages::Message
def initialize
super
puts "email constructor"
end
end
end
From within a controller in my Rails application I attempt to instantiate a new Email like so:
message = Messages::Emails::Email.new
I'm getting the following error:
LoadError (Unable to autoload constant Messages::Emails::Email, expected /home/ubuntu/workspace/app/messengers/messages/emails/email.rb to define it):
I assume this is something I have done incorrectly with the namespaces. Thanks in advance.
Rails ignores the folder name just below app. So, create app/messages/messages/message.rb something like:
module Messages
class Message
def initialize
puts "message constructor"
end
end
end
Then, app/messages/emails/email.rb should be:
module Emails
class Email < Messages::Message
def initialize
super
puts "email constructor"
end
end
end
Then you would do
Emails::Email.new
That file structure is a little unpretty, but it should do the trick.
Personally, I think I would create app/messages/messages/message_base.rb:
module Messages
class MessageBase
def initialize
puts "message constructor"
end
end
end
And app/messages/messages/email.rb:
module Messages
class Email < MessageBase
def initialize
super
puts "email constructor"
end
end
end
But, I suppose it's a matter of personal preference.

Ruby On Rails : Calling class method from concern

In Rails, is it possible to call methods from the class that included the concern, in the concern itself ? ie:
class Foo < ApplicationRecord
include Encryptable
def self.encrypted_attributes
%i[attr_1 attr_2]
end
end
module Encryptable
extend ActiveSupport::Concern
included do
self.encrypted_attributes do |attr|
define_method("#{attr}=") do |arg|
# do some stuff
end
define_method("#{attr}") do
# do some stuff
end
end
end
end
The issue is, when I try to do that, I get an error like :
*** NoMethodError Exception: undefined method 'encrypted_attributes' for #<Class:0x00005648d71c2430>
And, when debugging inside the concern, I get this something like this :
(byebug) self
Foo (call 'Foo' to establish a connection)
(byebug) self.class
Class
Ruby is a scripting language and the order matters. The following would do:
class Foo < ApplicationRecord
def self.encrypted_attributes
%i[attr_1 attr_2]
end
# OK, now we have self.encrypted_attributes defined
include Encryptable
end
More info: ActiveSupport::Concern#included.

How can I include the module with class to another class?

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

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.

Accessing Methods in Ruby Module

I'm writing my first Ruby module and I have this:
/app/module/test_modules/test.rb
test.rb looks similar to:
module TestModules
module Test
def test
puts 'this is a test'
end
end
end
When I call the following from console, I get:
(main)> TestModule::Test.test
//NoMethodError: private method `test' called for TestModules::Test:Module
How do I make test() visible?
You are calling a class method, whereas you defined test as an instance method. You could call it the way you want if you used the module via include or extend. This article does a good job explaining.
module TestModules
module Test
def self.test
puts 'this is a test'
end
end
end
Also,
1)
module TestModules
module Test
def test
puts 'this is a test'
end
module_function :test
end
end
2)
module TestModules
module Test
extend self
def test
puts 'this is a test'
end
end
end
The way that you have defined your method, it is a method on an instance of Test - thus it would work if you did:
blah = TestModule::Test.new
blah.test
note - and do use it this way, you would need to define Test as a class not a module
If you want the function to work on the class itself, then you need to define it like so:
def self.test
....
end
And then you can do TestModules::Test.test
the test method you defined is instance method...try this
module TestModules
module Test
def self.test
puts 'this is a test'
end
end
end
now you can call the method by this TestModules::Test.test

Resources