Module: IntrospectiveGrape::Traversal

Included in:
API
Defined in:
lib/introspective_grape/traversal.rb

Instance Method Summary collapse

Instance Method Details

#find_leaf(routes, record, params) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/introspective_grape/traversal.rb', line 32

def find_leaf(routes, record, params)
  return record unless routes.size > 1
  # For deeply nested routes we need to search from the root of the API to the leaf
  # of its nested associations in order to guarantee the validity of the relationship,
  # the authorization on the parent model, and the sanity of passed parameters.
  routes[1..-1].each_with_index do |r|
    if record && params[r.key]
      ref = r.reflection
      record = record.send(ref.name).where( id: params[r.key] ).first if ref
    end
  end

  verify_record_found(routes, params, record)
  record
end

#find_leaves(routes, record, params) ⇒ Object

For deeply nested endpoints we want to present the record being affected, these methods traverse down from the parent instance to the child model associations of the deeply nested route.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/introspective_grape/traversal.rb', line 6

def find_leaves(routes, record, params)
  # Traverse down our route and find the leaf's siblings from its parent, e.g.
  # project/#/teams/#/team_users ~> project.find.teams.find.team_users
  # (the traversal of the intermediate nodes occurs in find_leaf())
  return record if routes.size < 2 # the leaf is the root
  record = find_leaf(routes, record, params)
  if record
    assoc  = routes.last
    if assoc.many?
      leaves = record.send( assoc.reflection.name ).includes( default_includes(assoc.model) )
      verify_records_found(leaves, routes)
      leaves
    else
      # has_one associations don't return a CollectionProxy and so don't support
      # eager loading.
      record.send( assoc.reflection.name )
    end
  end
end

#verify_record_found(routes, params, record) ⇒ Object



48
49
50
51
52
# File 'lib/introspective_grape/traversal.rb', line 48

def verify_record_found(routes, params, record)
  if params[routes.last.key] && record.class != routes.last.model
    raise ActiveRecord::RecordNotFound.new("No #{routes.last.model.name} with ID '#{params[routes.last.key]}'")
  end
end

#verify_records_found(leaves, routes) ⇒ Object



26
27
28
29
30
# File 'lib/introspective_grape/traversal.rb', line 26

def verify_records_found(leaves, routes)
  unless (leaves.map(&:class) - [routes.last.model]).empty?
    raise ActiveRecord::RecordNotFound.new("Records contain the wrong models, they should all be #{routes.last.model.name}, found #{records.map(&:class).map(&:name).join(',')}")
  end
end