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

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

Constant Summary collapse

ActionNotFound =
Class.new StandardError
INSTANCE_RESPONSE =
proc do |context|
  builder                        =
    context.respond_to?(:builder) ? context.builder : nil
  context.response_object[:data] =
    build_resource(
      context: context,
      instance: context.instance,
      &builder
    )
  context.response_object.to_json
end
COLLECTION_RESPONSE =
proc do |context|
  builder                        = context.respond_to?(:builder) ? context.builder : nil
  context.response_object[:data] = build_resource_collection(
    context: context,
    collection: context.response_collection,
    include_cursors: (context.links.keys & [:first, :last, :next, :prev]).present?,
    &builder
  )
  context.response_object.to_json
end

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(klass) ⇒ Object



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

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



158
159
160
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 158

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

#actionsObject



162
163
164
165
166
167
168
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 162

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

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



154
155
156
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 154

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

#create(**options, &block) ⇒ Object



59
60
61
62
63
64
65
66
67
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 59

def create(**options, &block)
  define_action(:create, 'POST', '', **options, cacheable: false, example_input: :resource, &block).tap do |action|
    action.response(status: 201) do |context|
      instance_exec(context, &INSTANCE_RESPONSE).tap do
        response_headers['Location'] = context.response_object[:data][:links][:self]
      end
    end
  end
end

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



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

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(**options, &block) ⇒ Object



81
82
83
84
85
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 81

def delete(**options, &block)
  define_action(:delete, 'DELETE', '/:id', **options, cacheable: false, &block).tap do |action|
    action.response(status: 204)
  end
end

#documented_actionsObject



170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 170

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



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

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



141
142
143
144
145
146
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 141

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(**options, &block) ⇒ Object



53
54
55
56
57
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 53

def list(**options, &block)
  define_action(:list, 'GET', **options, cacheable: true, &block).tap do |action|
    action.response(status: 200, &COLLECTION_RESPONSE)
  end
end

#no_action_response(request) ⇒ Object



119
120
121
122
123
124
125
126
127
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 119

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



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

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

#process(request) ⇒ Object



87
88
89
90
91
92
93
94
95
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 87

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(**options, &block) ⇒ Object



69
70
71
72
73
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 69

def read(**options, &block)
  define_action(:read, 'GET', '/:id', **options, cacheable: true, &block).tap do |action|
    action.response(status: 200, &INSTANCE_RESPONSE)
  end
end

#remove_action(*names) ⇒ Object



148
149
150
151
152
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 148

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

#request_method_actions(request) ⇒ Object



135
136
137
138
139
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 135

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

#update(**options, &block) ⇒ Object



75
76
77
78
79
# File 'lib/jsonapionify/api/resource/definitions/actions.rb', line 75

def update(**options, &block)
  define_action(:update, 'PATCH', '/:id', **options, cacheable: false, example_input: :resource, &block).tap do |action|
    action.response(status: 200, &INSTANCE_RESPONSE)
  end
end