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



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/openstax/api/roar.rb', line 145

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

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

  case errors
  when ActiveModel::Errors, Lev::BetterActiveModelErrors
    hash[:errors] = errors.map do |attribute, 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



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

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



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

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
      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



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

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



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

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



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

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
      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 = {}) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 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

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

#standard_sort(*args) ⇒ Object

Raises:

  • (NotYetImplemented)


141
142
143
# File 'lib/openstax/api/roar.rb', line 141

def standard_sort(*args)
  raise NotYetImplemented
end

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



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

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