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!
Related
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
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.
I'm trying to access variables defined in class One, through inheritance, in class Two. I can't seem to find the right way of going about it - it seems to work for methods:
class One
class << self
def test
puts "I'm a method from class one"
end
end
end
end
And as a new object the variable is accessible:
class Two < One
test
end
#=> I'm a method from class one
class Test
attr_accessor :a
def initialize
#a = "hi"
end
end
Test.new.a
#=> "hi"
But I'm trying to do something like:
class One
class << self
a = "hi"
end
end
class Two < One
a
end
#=> NameError: undefined local variable or method `a' for Two:Class
For now I'm using class variables, but I'm sure there's a better way:
class One
##a = "hi"
end
class Two < One
##a
end
#=> "hi"
local and class instance variables wouldn't be accessible through inheritance in Ruby.
Limosine is an example of a class inheriting, a variable (brand) and a method, to_s
class Car
def initialize(brand)
#brand = brand
end
def to_s
"(##brand, ##model)"
end
end
class Limosine < Car
def initialize(brand, model)
super(brand)
#model = model
end
end
Use:
puts Merc.new("Mercedes", "Maybach")to_s
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])