Module: Serega::SeregaPlugins::ActiverecordPreloads

Defined in:
lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb,
lib/serega/plugins/activerecord_preloads/lib/preloader.rb

Overview

Plugin :activerecord_preloads

Automatically preloads associations to serialized objects

Every association declared with :preload is loaded once during serialization using ActiveRecord::Associations::Preloader, so there are no N+1 queries.

Examples:

class AppSerializer < Serega
  config.auto_preload = true
  plugin :activerecord_preloads
end

class AlbumSerializer < AppSerializer
  # no preloads
  attribute :title

  # preloads :downloads, as manually specified
  attribute :downloads_count, preload: :downloads, value: proc { |album| album.downloads.count }
end

class UserSerializer < AppSerializer
  # no preloads
  attribute :username

  # preloads :user_stats, as auto_preload is enabled for :delegate attributes
  attribute :comments_count, delegate: { to: :user_stats }

  # preloads :albums, as auto_preload is enabled for :serializer attributes
  attribute :albums, serializer: AlbumSerializer
end

UserSerializer.to_h(users)
# 1 query to load :user_stats for all users
# + 1 query to load :albums for all users
# + 1 query to load :downloads for all albums
# = 3 queries total, regardless of how many users/albums are serialized

Defined Under Namespace

Classes: ActiverecordArray, ActiverecordEnumerator, ActiverecordObject, ActiverecordRelation, Loader, Preloader

Class Method Summary collapse

Class Method Details

.after_load_plugin(serializer_class, **_opts) ⇒ void

This method returns an undefined value.

Registers the ActiveRecord preload handler

Parameters:

  • serializer_class (Class<Serega>)

    Current serializer class

  • _opts (Hash)

    Plugin options



89
90
91
92
93
# File 'lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb', line 89

def self.after_load_plugin(serializer_class, **_opts)
  serializer_class.preload_with do |objects, preloads|
    Preloader.preload(ActiverecordPreloads.records(serializer_class, objects), preloads)
  end
end

.before_load_plugin(serializer_class, **opts) ⇒ void

This method returns an undefined value.

Checks requirements to load plugin

Parameters:

  • serializer_class (Class<Serega>)

    Current serializer class

  • opts (Hash)

    plugin options



61
62
63
64
65
# File 'lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb', line 61

def self.before_load_plugin(serializer_class, **opts)
  opts.each_key do |key|
    raise SeregaError, "Plugin #{plugin_name.inspect} does not accept the #{key.inspect} option. No options are allowed"
  end
end

.load_plugin(serializer_class, **_opts) ⇒ void

This method returns an undefined value.

Applies plugin code to specific serializer

Parameters:

  • serializer_class (Class<Serega>)

    Current serializer class

  • _opts (Hash)

    Plugin options



76
77
78
# File 'lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb', line 76

def self.load_plugin(serializer_class, **_opts)
  require_relative "lib/preloader"
end

.plugin_nameSymbol

Returns Plugin name.

Returns:

  • (Symbol)

    Plugin name



49
50
51
# File 'lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb', line 49

def self.plugin_name
  :activerecord_preloads
end

.records(serializer_class, objects) ⇒ Array

The underlying records to preload onto. The :presenter plugin wraps every serialized object in a SimpleDelegator, but ActiveRecord's Preloader needs the real records, so unwrap them via #getobj when presenter is used. Objects are wrapped only when the Presenter class has custom methods.

Parameters:

  • serializer_class (Class<Serega>)

    Current serializer class

  • objects (Array)

    objects serialized at the current level

Returns:

  • (Array)

    the underlying records



107
108
109
110
111
112
# File 'lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb', line 107

def self.records(serializer_class, objects)
  return objects unless serializer_class.plugin_used?(:presenter)
  return objects unless serializer_class.custom_presenter?

  objects.map(&:__getobj__)
end