lundi 13 mai 2019

Performance difference in Concern method ran with Hook vs on Model?

Basically I notice a big performance difference in dynamically overriding a getter for ActiveRecord::Base models within an after_initialize hook and simply within the model itself.

Say I have the following Concern:

Module Greeter
  extend ActiveSupport::Concern

  included do
    after_initialize { override_get_greeting }
  end

  def override_get_greeting
    self.class::COLS.each do |attr|
      self.class.class_eval do
        define_method attr do
          "Hello #{self[attr]}!"
        end
      end
    end
  end

end

I then have the following model, consisting of a table with names.

CREATE TABLE 'names' ( 'name' varchar(10) );
INSERT INTO names (name) VALUES ("John")

class Name < ActiveRecord::Base
  COLS = 'name' 
  include Greeter
end

john = Name.where(name: 'John').first
john.name # Hello John!

This works fine. However, if I try to do this a more Rails way it is significantly slower.

Essentially, I want to simply pass a parameter into Greeter method that contains COLS and then overrides the getters. It'll look something like:

# Greeter
Module Greeter
  extend ActiveSupport::Concern

  def override_get_greeting(cols)
    cols.each do |attr|
      self.class.class_eval do
        define_method attr do
          "Hello #{self[attr]}!"
        end
      end
    end
  end

end

# Name
class Name < ActiveRecord::Base
  include Greeter
  override_get_greeting :[name]
end

Now Name.where(name: 'John').first.name # Hello John! is about 2 seconds slower on the first call.

I can't put my finger in it. I have an assumption that the the application is just slower to start with the first example, but not really sure.

I prefer the second example but the performance difference is a big no no.

Has anyone came across something like this?

Aucun commentaire:

Enregistrer un commentaire