In Ruby what is the difference between using def and define_method?

2

I understand that define_method creates a method dynamically, but ... in which cases would you use it?

What is the 'advantage' or what is different in the use, about creating a simple method with def ?

Please do not quote references from memory or pass links to the official documentation, because that just does not say what I'm asking.

    
asked by stack64 07.09.2016 в 12:16
source

1 answer

1

The advantage is that you can use variables in the creation of a method and create less code when there are several methods with minimal variations.
For example, imagine that I have a model User with an attribute status that defines if that user is in active or inactive state. I also need a couple of methods to help me:

  • Check if a user is in a specific state.
  • Check in the bd all users who are in a specific state.

Then the model that I describe to you would look something like this:

class User < ApplicationRecord

  # Con esto podría hacer user.active? y retornaría true/false dependiendo si el usuario está activo o no
  def active?
    status == 'active'
  end

  def inactive?
    status == 'inactive'
  end

  # Acá al ejecutar User.active retornaría todos los usuarios activos
  def self.active
    where(status: 'active')
  end

  def self.inactive
    where(status: 'inactive')
  end

end

Now imagine that there are new requirements and I need to add 5 more states for the user, for which the methods that I explained should also be defined. I could then create the methods, but it would be something repetitive, where the only thing that would change is the name of the state. In this case, some metaprogramming may be necessary and create the methods in the following way:

class User < ApplicationRecord

  # Creo un arreglo con los nombres de todos los estados posibles, incluidos los 5 nuevos
  STATUS = ['active', 'inactive', 'locked', 'deceased', 'admin', 'whatever', 'asdf']

  # Y luego itero en ese arreglo para crear los métodos necesarios para cada estado
  STATUS.each do |st|

    # define_singleton_method sirve para definir métodos de clase
    define_singleton_method st do
      where(status: st)
    end

    # define_method sirve para definir métodos de instancia
    define_method "#{st}?" do
      status == st
    end

  end

end

So in this way I saved myself from writing 14 methods that practically did the same thing, besides that there is a much cleaner code.

Another clear example is what Rails does internally with the variable names that one defines. For example for create route helpers as users_path or new_user_url when you define resources :users in the routes file.

Do not worry if in the first instance you feel that this has no greater utility or you do not find where to apply it. Its use is something that perhaps can not be visualized first, but as your code grows, you may feel the need to refactor your code and take up some metaprogramming, where it may become useful.

    
answered by 07.09.2016 / 15:22
source