Given a Class in Ruby:
class MyClass
def self.my_class_method
puts "class method"
end
private
def my_method
puts "regular method"
end
private_class_method :my_class_method
end
To access private methods I can call .send(:my_method) on the Class Object, but how does that work for class methods?
You should do:
class MyClass
def self.my_class_method
puts "class method"
end
private
def my_method
puts "regular method"
end
private_class_method :my_class_method
end
# to call class method
MyClass.send :my_class_method # => class method
# to call instance method
MyClass.new.send :my_method # => regular method
In Ruby, class(s) are also objects, so you can call the #send method on the class also.
In Ruby, you can define private class methods as
class MyClass
class << self
private
def my_class_method
puts "class method"
end
end
end
Or using thhis macro like method: private_class_method
First off, MyClass.send(:my_method) would not work. You have to send it to an instance: MyClass.new.send(:my_method).
Then, your my_class_method is not really private.
Ruby's semantic of private are somewhat different from what you might be used to in other languages. Since Ruby allows you to bypass encapsulation if you choose to, private just means that a method can only be called implicitly, without sending a message to an actual object.
For example:
class Example
def test
'foobar'
end
def hello
puts test # implicit receiver
puts self.test # explicit receiver
end
end
This is all good, but why is this important for your question?
Because you're declaring my_class_method explicitly on self. Doing so bypasses the private modifier, and the method is public. This means that you can just call it with:
MyClass.my_class_method
If you really need private class methods, then you can define them on the metaclass:
class MyClass
class << self
private
def my_class_method
puts "class method"
end
end
private
def my_method
puts "regular method"
end
end
This will make my_class_method actually private, and force you to invoke it with any of these:
MyClass.send :my_class_method
MyClass.class_exec { my_class_method }
MyClass.class_eval { my_class_method }
MyClass.class_eval "my_class_method"
Just for reference, that's not how you create a private class method.
class A
private
def self.foo
"foo"
end
end
A.foo # => "foo"
To create a private class method, you need to use private_class_method.
class A
def self.foo
"foo"
end
private_class_method :foo
end
A.foo # => private method `foo' called for A:Class
There are no such things as class methods. Class methods are just singleton methods of the class. But there are no such things as singleton methods either. Singleton methods are just instance methods of the singleton class. So, class methods are just instance methods of the class's singleton class.
Since there is no such thing as a class method, only instance methods, you already know what to do:
To access private methods I can call .send(:my_method) on the Class Object, but how does that work for class methods?
Related
Getting the following error when trying to call a private method inside the same class:
undefined local variable or method a_private_method' for AClass (NameError)`
Here the class:
class AClass
def self.public_method
file = a_private_method
end
private
def a_private_method
do something
end
end
You are trying to call an instance method from a class method, this does of course not work.
Try this
class AClass
class << self
def public_method
file = a_private_method
end
private
def a_private_method
# do something
end
end
end
You can also use self as the receiver similar to what you already did but pleases be aware that moving the method to the private part of your class does not work in this case. You could use private_class_method though.
class AClass
def self.public_method
file = a_private_method
end
def self.a_private_method
# do something
end
private_class_method :a_private_method
end
end
See https://jakeyesbeck.com/2016/01/24/ruby-private-class-methods and https://dev.to/adamlombard/ruby-class-methods-vs-instance-methods-4aje.
Why when I do self.method from a class, I get an undefined method `my_method' for MyModule::MyOtherModule::MyClass:Class
module MyModule
module OtherModule
class MyClass < Base
def my_method
end
def self.my_self_method
my_method
end
end
end
end
I call my_self_method with send from an herited [sic] class:
class Base
class << self
my_method(method_name)
send("my_self_#{method_name}")
end
end
end
I don't understand it.
In your code, you're defining one instance method (my_method), and one class method (my_self_method).
This means you can call:
MyClass.my_self_method
or
MyClass.new.my_method
If you want my_method to be callable from my_self_method, you could define it as:
def self.my_method
...
end
Then the following would be available:
def self.my_self_method
my_method
end
Here's another alternative. There's a comment that suggests it's bad practice to call new.my_method from within a class method, but I've seen a pattern that applies this that I find quite idiomatic, for example:
class MyClass
def self.run(the_variables)
new(the_variables).process
end
def initialize(the_variables)
# setup the_variables
end
def process
# do whatever's needed
end
end
This allows a simple entry point of MyClass.run(the_variables). If your use case seems suitable, a similar pattern for you would be:
module MyModule
module OtherModule
class MyClass < Base
def my_method
end
def self.my_self_method
new.my_method
end
end
end
end
I'm sure there's scope to disagree with this pattern, and would be interested to hear others' opinions in the comments.
Hope this helps clear a few things up #N.Safi.
class ApplicationController < ActionController::Base
protect_from_forgery #What is this syntax? When is this executed and how to create one?
end
class Comment < ActiveRecord::Base
belongs_to :post
attr_accessible :body, :commenter, :post
end
In the first case, I understand ApplicationController is a new Derived class of class called Base in the module ActionController. What happens in the next line? Is protect_from_forgery a method in base class or in module ActionController? What is it called? I couldn't find in ruby classes documentation. I tried creating a method in base class but got errors like below. How do I create such special commands which can be used in a class?
class Base
def foo
#name = "foo"
end
end
class Der < Base
foo
def bar
#dummy = "bar"
end
end
Error:
expr1.rb:62:in `<class:Der>': undefined local variable or method `foo' for Der:Class (NameError)
from expr1.rb:61:in `<main>'
protect_from_forgery is a class-method defined in one of the modules included in ActionController::Base and made available to the child class when you inherit from ActionController::Base.
This kind of methods in Rails are sometimes called "macro" as they are class methods that enables some specific feature (sometimes also using metaprogramming to define extra methods or helpers). In reality, the term "macro" is incorrect as Ruby has no macro. They are nothing else than class methods.
The most important detail to keep in mind is that, when they are used in the class-definition. these methods are run at code-evaluation and not at runtime.
class Base
def foo_instance
p "foo instance"
end
def self.foo_class
p "foo class"
end
end
class Der < Base
foo_class
def bar
p "bar"
end
end
Der.new.bar
will produce
"foo class"
"bar"
To create class methods you can do either of these.
class Base
def self.foo
end
end
class Base
class << self
def foo
end
end
end
Because they are class methods you call them on the class
Base.foo
So what you're talking about are "class methods" - class methods are methods that are defined on the class itself, not on the instance of the class. Note the following:
class Greeter
def initialize(name)
#name = name
end
def greet
"hello, #{#name}"
end
end
Greeter.new("bob").greet # => "hello, bob"
#greet is an instance method on the Greeter classes. However, .new is a "class method" - which is a method called on the class itself. Attempting to call .greet on the Greeter class would result in a NameError:
Greeter.greet # ! NameError
So if you want to define such a "class method", you have to use one of the following syntaxes:
class Greeter
def self.greet(name)
"hello, #{name}"
end
class << self
def greet(name)
"hello, #{name}"
end
end
class << Greeter
# same as above
end
end
def Greeter.greet(name)
"hello, #{name}"
end
Going back to the original question, if you reopen the greeter class, you can now use the .greet method:
class Greeter
greet "bob" # => "hello, bob"
end
This also applies for subclassing, as well:
class Host < Greeter
greet "bob" # => "hello, bob"
end
This is how Rails provides these methods - they define class methods on the base class, most often ActiveRecord::Base, which you can then use - explaining methods such as protect_from_forgery.
protect_from_forgery is a class method:Could look like this
def protect_from_forgery(options = {})
self.forgery_protection_strategy = protection_method_class(options[:with] || :null_session)
self.request_forgery_protection_token ||= :authenticity_token
prepend_before_action :verify_authenticity_token, options
append_after_action :verify_same_origin_request
end
So its inherited by application controller:
class ApplicationController < ActionController::Base
Your example could be written like this:
class Base
class << self
def foo
#name = "foo"
end
end
end
class Der < Base
foo #class method from Base
def bar
#dummy = "bar"
end
end
To see foo's values
Der.foo.inspect
Its inheritance. In your child class you can use all method inhertited from parrent class.
Firstly you can call methods on class instance.
In your example you can do sth like this:
base_object = Base.new
base_object.foo
der_object = Der.new
der_object.bar
but also thanks to inheritance you can do sth like this:
der_object.foo
Here is simple tutorial for ruby inheritance with examples:
http://rubylearning.com/satishtalim/ruby_inheritance.html
happy coding!
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
I am trying to do a custom active record macro. But it right now seems impossible set an instance variable from within it's block.. here is what i am trying to do.
module ActiveRecord
class Base
def self.included(base)
base.class.send(:define_method, :my_macro) do |args|
# instance_variable_set for the model instance that has called this
# macro using args
end
end
end
end
i have tried class_eval, instance_eval.. but nothing seems to work or i don't how to use them.
Thanks in advance.
Edit: Let me try to explain better. I have a class method. An instance of the class calls this method. Now, this class method should instruct the instance to set an instance variable for itself.
Edit- this is how i want o use the macro
class MyModel < ActiveRecord::Base
my_macro(*args)
def after_initialize
# use the value set in the macro as #instance variable
end
end
Is this what you are thinking of:
class DynamicAdd
def add_method
self.class_eval do
attr_accessor :some_method
end
end
end
You can then do the following:
k = DynamicAdd.new
k.some_method = "hi"
should result in an undefined method error.
But,
k = DynamicAdd.new
k.add_method
k.some_method = "hi"
should work.
You can use this same format to define other types of methods besides attr_accessors as well:
class DynamicAdd
def add_method
self.class_eval do
def some_method
return "hi"
end
end
end
end
Hm.. Isn't included() a Module method? I don't think you can use that in a class like you have written. If you want to create a class method you can do
class Base
def self.my_method
end
or
class Base
class << self
def my_method
end
end
If all you want to do is to add an instance variable to an existing object, then you can use #instance_variable_set
class Base
class << self
def my_method(instance_of_base, value)
instance_of_base.instance_variable_set "#x", value
end
end
end
a = Base.new
a.class.send(:my_method, *[a,4])