Method invocation in class definition? - ruby-on-rails

class Person < ActiveRecord::Base
validates :terms_of_service, :acceptance => true
end
In the above, what is validates from a Ruby standpoint? It's not a method definition, it's not a data definition or declaration. So, evidently it's a method invocation, right there in the body of the class. I have never seen a method invoked like that directly in a class (i.e. outside of a method definition), not even in the Ruby programming tutorial I'm going through now: http://ruby-doc.org/docs/ProgrammingRuby/.
So, if it's a method invocation, at what point is it being invoked? I tried the following as a test:
class Person
print "cat"
end
#p = Person.new
#q = Person.new
print "cat" is being executed exactly once, regardless if any actual Person objects are being declared or not, so evidently just when parsing the class definition, Ruby sees the method print and says, "OK I will just go ahead and execute this now" but never does so again.
So, where is the Ruby documentation that will help me understand what is going on with validates above?

In Ruby, class declarations are just chunks of code, executed in order.
It's important to remember that inside a class definition, self points to the class itself. validates is a class method of ActiveRecord. As the class is being defined, code in the definition is executed. The validates method resolves to a class method of ActiveRecord, so is called during class definition.
In your Person example, it will only print once, because you only define the class once.
Consider the following:
class Foo
def self.validates_nothing(sym)
(##syms ||= []) << sym
puts "!!! Here there be logic"
end
def validate
##syms.each { |s| puts s }
end
end
This defines a class with a class method validates_nothing, and an instance method, validate. validates_nothing just gathers whatever arguments are given it, validate just dumps them out.
class Bar < Foo
validates_nothing :anything
validates_nothing :at_all
end
This defines a subclass. Note that when the class method validates_nothing is called, it prints:
Here there be logic
Here there be logic
If we create a new bar and call validate, we get the expected output:
> Bar.new.validate
!!!anything
!!!at_all

Related

No method error for class variable defined with attr_accessor

I want to define methods dynamically using an array of strings.
Here is a simple piece of code that should achieve that.
class SomeClass
attr_accessor :my_array
def initialize(user, record)
#my_array=[]
end
my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
When I instantiate this class in the console, I get the following error
NoMethodError (undefined method `each' for nil:NilClass)
What is wrong with this code and how to make it work. any help highly appreciated :)
Edit 1:
What I ultimately want to achieve is to inherit from SomeClass and override my_array in the child class to dynamically define methods with its attributes like so
class OtherClass < SomeClass
my_array = %w[method1 method2 method3]
# Some mechanism to over write my_array.
end
And then use self.inherited to dynamically define methods in child class.
Is there a good way to achieve this?
In your code, you use an instance variable (#my_array) and an attr_accessor over it, and then try to access my_array from class level (that is, from the body of the class definition, outside of any methods). But instance variables only exist at instance level, so it is not available in the class scope.
One solution (the natural one, and the one which you would probably use in other languages) is to use a class variable: ##my_array. But class variables in ruby are a little problematic, so the best solution would be to make use of class instance variables, like that:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def initialize(user, record)
end
#my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
The syntax is a little tricky, so, if you look that up and it still doesn't makes sense, try just reading about scopes and using a regular class variable with ##.
Edit:
Ok, so, after your edit, it became more clear what you are trying to accomplish. A full working example is like follows:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def awesome_method
puts 'awesome'
end
def self.build!
#my_array.each do |element|
self.define_method("#{element}?".to_sym){ awesome_method }
end
end
end
class ChildClass < SomeClass
#my_array = %w[test little_test]
self.build!
end
child_instance = ChildClass.new
child_instance.test?
>> awesome
child_instance.little_test?
>> awesome
So, I've made some tweaks on SomeClass:
It does not need an initialize method
I tried to use the inherited hook for this problem. It won't ever work, because this hook is called as soon as "ChildClass < SomeClass" is written, and this must be before you can define something like #my_array = %w[test little_test]. So, I have added a self.build! method that must be called in the child instances so that they build their methods from my_array. This is inevitable, but I think it is also good, because it makes more explicit in the subclasses that you are doing something interesting there.
I think you want "define_method", not "alias_method".
awesome_method in passed in a block, which is ruby's way of doing functional programming.
With that done, ChildClass inherits from SomeClass, and it's instances have the dynamically created methods 'test?' and 'little_test?'.
You need to change my_array to class level accessible, in my case class constant.
class SomeClass
DYNAMIC_METHOD_NAMES = %w(method_a method_b method_C).freeze
def initialize(user, record)
end
DYNAMIC_METHOD_NAMES.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end

How rails(ActiveRecord) defines the class method on models and how to remove one of them if needed

I am trying to figure this out on my journey to rails and ruby's deeper understanding.
What i know is that we can check if a method is defined in a ruby class by calling: method_defined? on the object. As all classes are also objects of class Class we can do same for class methods. For example if class Foo defines bar class method, this is what happens:
Foo.method_defined? :bar #-> true
But when applying same on models which are inherited from ActiveRecord::Base(directly or indirectly). this results in:
User.method_defined? :all #-> false
User.method_defined? :count #-> false
I can see the all method defined here, i am struggling to match the dots and make sense of whats going on. And how these methods work on models when they are not implemented as class methods neither is there any funky business of method_missing is going on(as it seems).
While on it, if i can get same explanation for instance methods which rails adds for model objects, like name method in User.first.name(assuming user table has name column). Would be a plus.
Lastly, some word on how to remove one of these methods if we ever need to.
EXTRA: If i can also get to know how to reset the User class to have the method defined again after removing, like if i remove count method with the suggestion from comments: User.instance_eval { undef :count } i also want to be able to redefine this back. Or kind of reset the User class. load 'app/models/user.rb' does not do the job here.
Update: I figured out how to reset the class after undefining a method in the eigenclass of model User before doing load 'app/models/user.rb' i had to explicitly do Object.send(:remove_const, :User) so ruby removes the class entirely than do the load thing.
Still struggling to digest all this and especially how the rails implementation works.
No magic here
module X
def test
end
end
class A
extend X
end
class B
include X
end
A.method_defined? :test #false
B.method_defined? :test #true
so it's not defined because it's a class method and class methods are defined in the singleton class.
method_defined? check if the method is defined in the class or its ancestors only.
B.ancestors #[B, X, Object, Kernel, BasicObject]
A.ancestors #[A, Object, Kernel, BasicObject]
so simply because it's a class method
UPDATE: Adding more trace to How all is defined
the method all is defined as mentioned in https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activerecord/lib/active_record/scoping/named.rb
this module extends ActiveSupport::Concern which mean if you included this module the methods in ClassMethods will be added as class methods to the includer (more about this https://api.rubyonrails.org/classes/ActiveSupport/Concern.html)
in the active record entry point here https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activerecord/lib/active_record.rb#L151 the module Named is autoloaded inside Scoping module which resulted in having module called ActiveRecord::Scoping::Named the module mentioned above
here in the base class, the Scoping module is included https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activerecord/lib/active_record/base.rb#L298 which define all as class method
so it's similar to the simple code above but using some of ActiveSupport magic like autoloading , egarloading and concerns.
We can remove a method using
User.instance_eval { undef :count }
and can redefine if its in parent class using
User.instance_eval do
def count
super
end
end
Hope it would help you
Not sure, but. Method method_defined? cares about instance public methods. Instead, if you want to check is any object responds to a method (as a class it's also object) use respond_to?.

"transaction do" without explicit receiver

According to the docs, in Rails models, transactions are made on either classes descending from ActiveRecord::Base or any instance of such a class. Some blog posts on the subject list the following alternatives:
ActiveRecord::Base.transaction do
User.transaction doUser descends from ActiveRecord::Base
#user.transaction do#user is an instance of User
self.class.transaction dowithin any model.rb where self is e.g. User
self.transaction dowithin any model.rb where self is e.g. an instance of User)
However, I'm missing another variation on this list: How about just transaction do within model.rb?
class User < ApplicationRecord
def foo
transaction do
# do stuff
end
end
end
Am I right to assume, that the self. is not really necessary since in the scope of a model instance method, self is always the model instance by default?
In Ruby the implicit recipient in an instance method is always the instance:
class Thing
def foo
inspect
end
end
irb(main):026:0> Thing.new.foo
=> "#<Thing:0x007fde95955828>"
Am I right to assume, that the self. is not really necessary since in
the scope of a model instance method, self is always the model
instance by default?
There is always an implicit recipient (self) in ruby. What it is depends on the context. In class methods its the class. Its "main" (the global object) if you are not in a class or module.
class Foo
inspect
end
# => "Foo"
def foo
inspect
end
# => "main"
You only have to explicitly use self where there is a need to disambiguate (like for example self.class). But there are many situations where it can help the readability of your code.
All of the options above are pretty much functionally equivalent:
ActiveRecord::Base.transaction connects to the DB for that environment from database.yml or ENV["DATABASE_URL"].
User.transaction or class.transaction can be used if you want to have different connections per model class or just don't like typing. All it really does is connection.transaction(options, &block).
The instance level self.transaction or #user.transaction just proxies to the class method. All it really does is self.class.transaction(options,&block);

Not understanding Classes, Modules, and the class << self method

I have the following code:
class MyClass
module MyModule
class << self
attr_accessor :first_name
def myfunction
MyModule.first_name = "Nathan"
end
end
end
end
When I call the method myfunction like so, it works fine:
> me = MyClass::MyModule.myfunction
=> "Nathan"
> me
=> "Nathan"
But if I removed the class << self and add a self. prefix to myfunction, it doesn't work.
For example:
class MyClass
module MyModule
attr_accessor :first_name
def self.myfunction
MyModule.first_name = "Nathan"
end
end
end
> me = MyClass::MyModule.myfunction
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module
I'm trying to understand the class << self method. I thought it was a way add the self. prefix to the all the methods inside of it, but if that was true, why doesn't it work if I remove it and prefix each method with self. manually?
Thanks in advance for your help.
This is because your attr_accessor :first_name is also wrapped by the class << self.
To do it the way you suggest, you can use mattr_accessor like so:
require 'active_support'
class MyClass
module MyModule
mattr_accessor :first_name
def self.myfunction
MyModule.first_name = "Nathan"
end
end
end
To better understand how you can achieve what you want, take a look at the following example:
module PrintingModule
def self.included(object)
object.extend(ClassMethods)
end
module ClassMethods
def class_method_of_class
puts "I am class #{self.name}"
end
end
def instance_method_of_class
puts "My name is: #{#name}"
end
class << self
def static_module_method
puts "Printer version 1.0"
end
end
end
class SomeObject
include PrintingModule
def initialize(name)
#name = name
end
end
object = SomeObject.new("Something")
object.instance_method_of_class
SomeObject.class_method_of_class
PrintingModule.static_module_method
I hope it's more clear now, note that this is just one of possible way (there are others)
UPDATE:
I'll try to be more specific. When you define instance/singleton methods on module, what you are really doing is that you are defining instance methods of class which will include that module and on the other hand, class methods defined on module will become class methods of that module. The second think to know is that attr_accessor creates instance method for getter and setter of the given parameter.
Now to answer one part of your question, in the first example you are creating 3 class methods on module's class. In the second one, you are creating 1 class method where you are trying to access another class method (setter), but your getters and setters are defined as instance methods = they will become instance of method of class which will include your module, you cannot get to them this way = you have no access to your getters and setters.
As for explanation of self, well I'm not that skilled, but as far as I know, when you use "class << self" you are opening eigenclass (each object has it's own anynonymous one) of the object (note that Class, modules or instances of classes are of course objects too) where you are defining instance methods. Class method of object in Ruby = instance method of the eigenclass of the object. So you can do this for example:
text = "something"
class << text
def say_hi
puts "Hi!"
end
end
text.say_hi
When you create instance of class (String in that example), that instance gets it's own unique anonymous class which is subclass of that Class. In the example, you have defined instance method on the eigenclass of the anonymous subclass of String class. So you can use method "say_hi" on the text object but not on the String class. So "class << self" is opening those eigenclasses.
On the other hand, "self" alone just represents an object in the current context, which means the same in some scenarios (for example yours). As for self.included method, it is just a callback method which gets called when the module is included in the class with a parameter representing the object (here class SomeObject).
I hope that I have answered at least part of your question.
More information here:
Difference between 'self.method_name' and 'class << self' in Ruby

Class methods in Ruby on Rails 3 — I'm totally lost!

Background here.
In the above link, the following example is given:
class << self
def by_author(author)
where(:author_id => author.id)
end
end
Aside from that syntax being foreign to a beginner like me — I had always thought class methods were defined with def self.my_class_method — where can I find documentation about class methods in Ruby on Rails?
As far as I know, class methods are always called on the class itself (MyClass.my_class_method), but if class methods in Rails are chainable, it seems as though something else must be going on here!
Edit:
I suppose I sort of cheated by making that comment about the syntax for class methods. I'm really asking how Rails makes a class method chainable — I understand how method chaining works, but not how Rails can allow you to chain class methods without actually returning the class object itself after each "link" in the chain.
Class methods in Ruby are really just members of the singleton class, and doing class << self involves opening the singleton class directly and adding to it, removing the need to declare it in each method definition.
This article on Ruby singletons does a good job explaining.
As far as class methods being chainable, that isn't something specific to class methods, the second method call is simply called on the object returned from the first. For example:
bar = foo.do_something.do_more
is equivalent to:
tmp = foo.do_something
bar = tmp.do_more
In Rails, this chainability is most often used for building SQL queries (e.g., with where or order, etc.). This is achieved because each of these methods returns an ActiveRecord Relation.
The reason
foo.scoped.my_foo_class_method
works is because of ActiveRecord::Relation#method_missing doing the following:
elsif #klass.respond_to?(method)
scoping { #klass.send(method, *args, &block) }
Which checks if the ActiveRecord class responds to the method called, and if so, calls that.
Having class << self is also another way to define your methods so that you do not have to call "def self.my_method" or "def MyClass.my_method" for every single method that you are defining as a class method. Instead of calling
def self.my_method1
end
def self.my_method2
end
class << self
def my_method1
end
def my_method2
end
end
Cheers!
The following two bits of code are equivalent.
Using self.method:
class Hello
def self.world
puts "Hello, World!"
end
end
Using class << self:
class Hello
class << self
def world
puts "Hello, World!"
end
end
end
The only difference is readability, as well as the ease in refactoring.
The class << self technique is often used when metaprogramming.
There is another thread that explains this. class << self vs self.method with Ruby: what's better?

Resources