Class: Brainstem::PresenterCollection

Inherits:
Object
  • Object
show all
Defined in:
lib/brainstem/presenter_collection.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#default_max_filter_and_search_pageObject

Returns the value of attribute default_max_filter_and_search_page



15
16
17
# File 'lib/brainstem/presenter_collection.rb', line 15

def default_max_filter_and_search_page
  @default_max_filter_and_search_page
end

#default_max_per_pageInteger

Returns The maximum number of objects that can be requested in a single presented hash.

Returns:

  • (Integer)

    The maximum number of objects that can be requested in a single presented hash.



9
10
11
# File 'lib/brainstem/presenter_collection.rb', line 9

def default_max_per_page
  @default_max_per_page
end

#default_per_pageInteger

Returns The default number of objects that will be returned in the presented hash.

Returns:

  • (Integer)

    The default number of objects that will be returned in the presented hash.



13
14
15
# File 'lib/brainstem/presenter_collection.rb', line 13

def default_per_page
  @default_per_page
end

Instance Method Details

#add_presenter_class(presenter_class, *klasses) ⇒ Object

Parameters:

  • presenter_class (String, Class)

    The presenter class that knows how to present all of the classes given in klasses.

  • klasses (*Class)

    One or more classes that can be presented by presenter_class.



123
124
125
126
127
# File 'lib/brainstem/presenter_collection.rb', line 123

def add_presenter_class(presenter_class, *klasses)
  klasses.each do |klass|
    presenters[klass.to_s] = presenter_class
  end
end

#brainstem_key_for!(klass) ⇒ Object

Raises:

  • (ArgumentError)


140
141
142
143
144
# File 'lib/brainstem/presenter_collection.rb', line 140

def brainstem_key_for!(klass)
  presenter = presenters[klass.to_s]
  raise(ArgumentError, "Unable to find a presenter for class #{klass}") unless presenter
  presenter.configuration[:brainstem_key] || klass.table_name
end

#for(klass) ⇒ Brainstem::Presenter?

Returns A new instance of the Presenter that knows how to present the class klass, or nil if there isn't one.

Returns:

  • (Brainstem::Presenter, nil)

    A new instance of the Presenter that knows how to present the class klass, or nil if there isn't one.



130
131
132
# File 'lib/brainstem/presenter_collection.rb', line 130

def for(klass)
  presenters[klass.to_s].try(:new)
end

#for!(klass) ⇒ Brainstem::Presenter

Returns A new instance of the Presenter that knows how to present the class klass.

Returns:

  • (Brainstem::Presenter)

    A new instance of the Presenter that knows how to present the class klass.

Raises:

  • (ArgumentError)

    if there is no known Presenter for klass.



136
137
138
# File 'lib/brainstem/presenter_collection.rb', line 136

def for!(klass)
  self.for(klass) || raise(ArgumentError, "Unable to find a presenter for class #{klass}")
end

#presentersHash

Returns The presenters this collection knows about, keyed on the names of the classes that can be presented.

Returns:

  • (Hash)

    The presenters this collection knows about, keyed on the names of the classes that can be presented.



117
118
119
# File 'lib/brainstem/presenter_collection.rb', line 117

def presenters
  @presenters ||= {}
end

#presenting(name, options = {}) { ... } ⇒ Hash

The main presentation method, converting a model name and an optional scope into a hash structure, ready to be converted into JSON. If searching, Brainstem filtering, only, pagination, and ordering are skipped and should be implemented with your search solution. All request options are passed to the search block for your convenience.

Parameters:

  • name (Class, String)

    Either the ActiveRecord Class itself, or its pluralized table name as a string.

  • options (Hash) (defaults to: {})

    The options that will be applied as the objects are converted.

Options Hash (options):

  • :params (Hash)

    The params hash included in a request for the presented object.

  • :model (ActiveRecord::Base)

    The model that is being presented (if different from name).

  • :max_per_page (Integer)

    The maximum number of items that can be requested by params[:per_page].

  • :per_page (Integer)

    The number of items that will be returned if params[:per_page] is not set.

  • :apply_default_filters (Boolean)

    Determine if Presenter's filter defaults should be applied. On by default.

  • :primary_presenter (Brainstem::Presenter)

    The Presenter to use for filters and sorts. If unspecified, the :model or name will be used to find an appropriate Presenter.

Yields:

  • Must return a scope on the model name, which will then be presented.

Returns:

  • (Hash)

    A hash of arrays of hashes. Top-level hash keys are pluralized model names, with values of arrays containing one hash per object that was found by the given given options.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/brainstem/presenter_collection.rb', line 37

def presenting(name, options = {}, &block)
  options[:params] = HashWithIndifferentAccess.new(options[:params] || {})
  check_for_old_options!(options)
  set_default_filters_option!(options)
  presented_class = (options[:model] || name)
  presented_class = presented_class.classify.constantize if presented_class.is_a?(String)
  scope = presented_class.instance_eval(&block)
  count = 0

  # grab the presenter that knows about filters and sorting etc.
  options[:primary_presenter] ||= for!(presented_class)

  # table name will be used to query the database for the filtered data
  options[:table_name] = presented_class.table_name

  options[:default_per_page] = default_per_page
  options[:default_max_per_page] = default_max_per_page
  options[:default_max_filter_and_search_page] = default_max_filter_and_search_page

  strategy = get_strategy(options, scope)
  primary_models, count = strategy.execute(scope)

  # Determine if an exception should be raised on an empty result set.
  if options[:raise_on_empty] && primary_models.empty?
    raise options[:empty_error_class] || ActiveRecord::RecordNotFound
  end

  structure_response(presented_class, primary_models, strategy, count, options)
end

#structure_response(presented_class, primary_models, strategy, count, options) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/brainstem/presenter_collection.rb', line 67

def structure_response(presented_class, primary_models, strategy, count, options)
  # key these models will use in the struct that is output
  brainstem_key = brainstem_key_for!(presented_class)

  # filter the incoming :includes list by those available from this Presenter in the current context
  selected_associations = filter_includes(options)

  optional_fields = filter_optional_fields(options)
  page_size = strategy.calculate_per_page

  struct = {
    'count' => count,
    'results' => [],
    brainstem_key => {},
    'meta' => {
      'count' => count,
      'page_count' => count > 0 ? (count.to_f / page_size).ceil : 0,
      'page_number' => count > 0 ? options[:params].fetch(:page, 1).to_i : 0,
      'page_size' => page_size,
    }
  }

  # Build top-level keys for all requested associations.
  selected_associations.each do |association|
    struct[brainstem_key_for!(association.target_class)] ||= {} unless association.polymorphic?
  end

  if primary_models.length > 0
    associated_models = {}
    presented_primary_models = options[:primary_presenter].group_present(primary_models,
                                                                         selected_associations.map(&:name),
                                                                         optional_fields: optional_fields,
                                                                         load_associations_into: associated_models)

    struct[brainstem_key] = presented_primary_models.each.with_object({}) { |model, obj| obj[model['id']] = model }
    struct['results'] = presented_primary_models.map { |model| { 'key' => brainstem_key, 'id' => model['id'] } }

    associated_models.each do |association_brainstem_key, associated_models_hash|
      presenter = for!(associated_models_hash.values.first.class)
      struct[association_brainstem_key] ||= {}
      presenter.group_present(associated_models_hash.values).each do |model|
        struct[association_brainstem_key][model['id']] ||= model
      end
    end
  end

  struct
end

#validate!Object

Raises:

  • (StandardError)

    if any presenter in this collection is invalid.



147
148
149
150
151
152
153
154
155
156
# File 'lib/brainstem/presenter_collection.rb', line 147

def validate!
  errors = []
  presenters.each do |name, klass|
    validator = Brainstem::PresenterValidator.new(klass)
    unless validator.valid?
      errors += validator.errors.full_messages.map { |error| "#{name}: #{error}" }
    end
  end
  raise "PresenterCollection invalid:\n - #{errors.join("\n - ")}" if errors.length > 0
end