Module: OpenStax::Api::Roar

Included in:
V1::ApiController
Defined in:
lib/openstax/api/roar.rb

Instance Method Summary collapse

Instance Method Details

#render_api_errors(errors, status = :unprocessable_entity) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/openstax/api/roar.rb', line 149

def render_api_errors(errors, status = :unprocessable_entity)
  return if errors.blank?

  hash = { status: Rack::Utils.status_code(status) }

  case errors
  when ActiveModel::Errors
    hash[:errors] = errors.map do |error|
      attribute = error.attribute
      message = error.message

      {
        code: "#{attribute.to_s}_#{message.to_s.gsub(/[\s-]/, '_').gsub(/[^\w]/, '')}",
        message: errors.full_message(attribute, message)
      }
    end
  when Lev::Errors
    hash[:errors] = errors.map do |error|
      { code: error.code, message: error.message, data: error.data }
    end
  else
    hash[:errors] = [errors].flatten.map do |error|
      error.is_a?(Hash) ? error :
                          { code: error.to_s.underscore, message: error.to_s.humanize }
    end
  end

  render json: hash, status: status
end

#standard_create(model, represent_with = nil, options = {}) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/openstax/api/roar.rb', line 45

def standard_create(model, represent_with=nil, options={})
  represent_with_options = { user_options: options, represent_with: represent_with }

  model.class.transaction do
    consume!(model, represent_with_options.dup)
    yield model if block_given?
    OSU::AccessPolicy.require_action_allowed!(:create, current_api_user, model)

    if model.save
      respond_with model, { status: :created, location: nil }.merge(represent_with_options)
    else
      render_api_errors(model.errors)
    end
  end
end

#standard_destroy(model, represent_with = nil, options = {}) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/openstax/api/roar.rb', line 99

def standard_destroy(model, represent_with=nil, options={})
  OSU::AccessPolicy.require_action_allowed!(:destroy, current_api_user, model)

  return render_api_errors(code: "#{model.model_name.element}_is_already_deleted",
                           message: "#{model.model_name.human} is already deleted") \
    if model.respond_to?(:deleted?) && model.deleted?

  responder_options = { responder: ResponderWithPutPatchDeleteContent }
  represent_with_options = { user_options: options, represent_with: represent_with }

  model.with_lock do
    if model.destroy
      model.send :clear_association_cache
      yield model if block_given?
      respond_with model, responder_options.merge(represent_with_options)
    else
      render_api_errors(model.errors)
    end
  end
end

#standard_index(relation, represent_with, options = {}) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/openstax/api/roar.rb', line 12

def standard_index(relation, represent_with, options={})
  model_klass = relation.base_class
  OSU::AccessPolicy.require_action_allowed!(:index, current_api_user, model_klass)

  represent_with_options = { user_options: options, represent_with: represent_with }

  relation.each do |item|
    # Must be able to read each record
    OSU::AccessPolicy.require_action_allowed!(:read, current_api_user, item)
  end

  respond_with(Lev::Outputs.new(items: relation), represent_with_options)
end

#standard_nested_create(model, container_association, container, represent_with = nil, options = {}) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/openstax/api/roar.rb', line 61

def standard_nested_create(model, container_association, container,
                           represent_with=nil, options={})
  # Must be able to update the container
  OSU::AccessPolicy.require_action_allowed!(:update, current_api_user, container)

  model.send("#{container_association.to_s}=", container)

  standard_create(model, represent_with, options)
end

#standard_read(model, represent_with = nil, use_timestamp_for_cache = false, options = {}) ⇒ Object



71
72
73
74
75
76
# File 'lib/openstax/api/roar.rb', line 71

def standard_read(model, represent_with=nil, use_timestamp_for_cache=false, options={})
  OSU::AccessPolicy.require_action_allowed!(:read, current_api_user, model)

  respond_with(model, { user_options: options, represent_with: represent_with }) \
    if !use_timestamp_for_cache || stale?(model, template: false)
end

#standard_restore(model, represent_with = nil, options = {}) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/openstax/api/roar.rb', line 120

def standard_restore(model, represent_with=nil, options={})
  OSU::AccessPolicy.require_action_allowed!(:restore, current_api_user, model)

  return render_api_errors(code: "#{model.model_name.element}_is_not_deleted",
                           message: "#{model.model_name.human} is not deleted") \
    if !model.respond_to?(:deleted?) || !model.deleted?

  recursive = options.has_key?(:recursive) ? options[:recursive] : true

  responder_options = { responder: ResponderWithPutPatchDeleteContent }
  represent_with_options = {
    user_options: options.except(:recursive), represent_with: represent_with
  }

  model.with_lock do
    if model.restore(recursive: recursive)
      model.send :clear_association_cache
      yield model if block_given?
      respond_with model, responder_options.merge(represent_with_options)
    else
      render_api_errors(model.errors)
    end
  end
end

#standard_search(klass, routine, represent_with, options = {}) {|outputs| ... } ⇒ Object

Yields:

  • (outputs)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/openstax/api/roar.rb', line 26

def standard_search(klass, routine, represent_with, options={})
  user = current_api_user
  OSU::AccessPolicy.require_action_allowed!(:search, user, klass)

  represent_with_options = { user_options: options, represent_with: represent_with }

  result = routine.call(params, options)
  return render_api_errors(result.errors) if result.errors.any?

  outputs = result.outputs
  outputs.items.each do |item|
    OSU::AccessPolicy.require_action_allowed!(:read, user, item)
  end

  yield outputs if block_given?

  respond_with outputs, { status: :ok, location: nil }.merge(represent_with_options)
end

#standard_sort(*args) ⇒ Object

Raises:

  • (NotYetImplemented)


145
146
147
# File 'lib/openstax/api/roar.rb', line 145

def standard_sort(*args)
  raise NotYetImplemented
end

#standard_update(model, represent_with = nil, options = {}) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/openstax/api/roar.rb', line 78

def standard_update(model, represent_with=nil, options={})
  # Must be able to update the record before and after the update itself
  OSU::AccessPolicy.require_action_allowed!(:update, current_api_user, model)

  responder_options = { responder: ResponderWithPutPatchDeleteContent }
  represent_with_options = { user_options: options, represent_with: represent_with }

  model.with_lock do
    consume!(model, represent_with_options.dup)
    yield model if block_given?
    OSU::AccessPolicy.require_action_allowed!(:update, current_api_user, model)

    if model.save
      # http://stackoverflow.com/a/27413178
      respond_with model, responder_options.merge(represent_with_options)
    else
      render_api_errors(model.errors)
    end
  end
end