Module: JSONAPIonify::Api::Resource::Definitions::Actions

Defined in:
lib/jsonapionify/api/resource/definitions/actions.rb

Constant Summary collapse

ActionNotFound =
Class.new StandardError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(klass) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 8

def self.extended(klass)
  klass.class_eval do
    extend JSONAPIonify::InheritedAttributes
    include JSONAPIonify::Callbacks
    define_callbacks(
      :request, :exception, :response,
      :list, :commit_list,
      :create, :commit_create,
      :read, :commit_read,
      :update, :commit_update,
      :delete, :commit_delete,
      :show, :commit_show,
      :add, :commit_add,
      :remove, :commit_remove,
      :replace, :commit_replace
    )
    inherited_array_attribute :action_definitions
  end
end

Instance Method Details

#action(name) ⇒ Object



189
190
191
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 189

def action(name)
  actions.find { |action| action.name == name }
end

#actionsObject



193
194
195
196
197
198
199
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 193

def actions
  return [] if action_definitions.blank?
  action_definitions.select do |action|
    action.only_associated == false ||
      (respond_to?(:rel) && action.only_associated == true)
  end
end

#after(*action_names, &block) ⇒ Object



123
124
125
126
127
128
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 123

def after(*action_names, &block)
  return after_request &block if action_names.blank?
  action_names.each do |action_name|
    send("after_#{action_name}", &block)
  end
end

#before(*action_names, &block) ⇒ Object



130
131
132
133
134
135
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 130

def before(*action_names, &block)
  return before_request &block if action_names.blank?
  action_names.each do |action_name|
    send("before_#{action_name}", &block)
  end
end

#call_action(name, request, **context_overrides) ⇒ Object



185
186
187
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 185

def call_action(name, request, **context_overrides)
  action(name).call(self, request, **context_overrides)
end

#create(content_type: nil, only_associated: false, callbacks: true, &block) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 50

def create(content_type: nil, only_associated: false, callbacks: true, &block)
  options = {
    content_type:    content_type,
    only_associated: only_associated,
    callbacks:       callbacks,
    cacheable:       false,
    example_input:   :resource
  }
  define_action(:create, 'POST', **options, &block).tap do |action|
    action.response status: 201 do |context|
      builder                        = context.respond_to?(:builder) ? context.builder : nil
      context.response_object[:data] = build_resource(context, context.instance, fields: context.fields, &builder)
      response_headers['Location']   = build_url(context, context.instance)
      context.response_object.to_json
    end
  end
end

#define_action(name, *args, **options, &block) ⇒ Object



137
138
139
140
141
142
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 137

def define_action(name, *args, **options, &block)
  Action.new(name, *args, **options, &block).tap do |new_action|
    action_definitions.delete new_action
    action_definitions << new_action
  end
end

#delete(content_type: nil, only_associated: false, callbacks: true, &block) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 101

def delete(content_type: nil, only_associated: false, callbacks: true, &block)
  options = {
    content_type:    content_type,
    only_associated: only_associated,
    callbacks:       callbacks,
    cacheable:       false
  }
  define_action(:delete, 'DELETE', '/:id', **options, &block).tap do |action|
    action.response status: 204
  end
end

#documented_actionsObject



201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 201

def documented_actions
  api.eager_load
  relationships = descendants.select { |descendant| descendant.respond_to? :rel }
  rels          = relationships.each_with_object([]) do |rel, ary|
    rel.actions.each do |action|
      ary << [action, "#{rel.rel.owner.type}/:id", [rel, rel.rel.name, false, "#{action.name} #{rel.rel.owner.type.singularize.possessive} #{rel.rel.name}"]]
    end
  end
  actions.map do |action|
    [action, '', [self, type, true, "#{action.name} #{type}"]]
  end + rels
end

#find_supported_action(request) ⇒ Object



144
145
146
147
148
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 144

def find_supported_action(request)
  actions.find do |action|
    action.supports?(request, base_path, path_name, supports_path?)
  end
end

#find_supported_relationship(request) ⇒ Object



172
173
174
175
176
177
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 172

def find_supported_relationship(request)
  relationship_definitions.find do |rel|
    relationship = self.relationship(rel.name)
    relationship != self && relationship.path_actions(request).present?
  end
end

#list(content_type: nil, only_associated: false, callbacks: true, &block) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 28

def list(content_type: nil, only_associated: false, callbacks: true, &block)
  options = {
    content_type:    content_type,
    only_associated: only_associated,
    callbacks:       callbacks,
    cacheable:       true
  }
  define_action(:list, 'GET', **options, &block).tap do |action|
    action.response status: 200 do |context|
      builder                        = context.respond_to?(:builder) ? context.builder : nil
      context.response_object[:data] = build_collection(
        context,
        context.response_collection,
        fields:          context.fields,
        include_cursors: (context.links.keys & [:first, :last, :next, :prev]).present?,
        &builder
      )
      context.response_object.to_json
    end
  end
end

#no_action_response(request) ⇒ Object



150
151
152
153
154
155
156
157
158
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 150

def no_action_response(request)
  if request_method_actions(request).present?
    Action.error :unsupported_media_type
  elsif self.path_actions(request).present?
    Action.error :forbidden
  else
    Action.error :not_found
  end
end

#path_actions(request) ⇒ Object



160
161
162
163
164
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 160

def path_actions(request)
  actions.select do |action|
    action.supports_path?(request, base_path, path_name, supports_path?)
  end
end

#process(request) ⇒ Object



113
114
115
116
117
118
119
120
121
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 113

def process(request)
  if (action = find_supported_action(request))
    action.call(self, request)
  elsif (rel = find_supported_relationship(request))
    relationship(rel.name).process(request)
  else
    no_action_response(request).call(self, request)
  end
end

#read(content_type: nil, only_associated: false, callbacks: true, &block) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 68

def read(content_type: nil, only_associated: false, callbacks: true, &block)
  options = {
    content_type:    content_type,
    only_associated: only_associated,
    callbacks:       callbacks,
    cacheable:       true
  }
  define_action(:read, 'GET', '/:id', **options, &block).tap do |action|
    action.response status: 200 do |context|
      builder                        = context.respond_to?(:builder) ? context.builder : nil
      context.response_object[:data] = build_resource(context, context.instance, fields: context.fields, &builder)
      context.response_object.to_json
    end
  end
end

#remove_action(*names) ⇒ Object



179
180
181
182
183
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 179

def remove_action(*names)
  action_definitions.delete_if do |action_definition|
    names.include? action_definition.name
  end
end

#request_method_actions(request) ⇒ Object



166
167
168
169
170
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 166

def request_method_actions(request)
  path_actions(request).select do |action|
    action.supports_request_method?(request)
  end
end

#update(content_type: nil, only_associated: false, callbacks: true, &block) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 84

def update(content_type: nil, only_associated: false, callbacks: true, &block)
  options = {
    content_type:    content_type,
    only_associated: only_associated,
    callbacks:       callbacks,
    cacheable:       false,
    example_input:   :resource
  }
  define_action(:update, 'PATCH', '/:id', **options, &block).tap do |action|
    action.response status: 200 do |context|
      builder                        = context.respond_to?(:builder) ? context.builder : nil
      context.response_object[:data] = build_resource(context, context.instance, fields: context.fields, &builder)
      context.response_object.to_json
    end
  end
end