Last active
July 11, 2017 20:38
-
-
Save kavunshiva/14720485f982730431963584f728fa04 to your computer and use it in GitHub Desktop.
persisting position to a database
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Api::V1::PositionsController < ApplicationController | |
before_action :authorize_device! | |
def index | |
positions = Position.where(device_id: params[:id]).order(time: :desc) | |
render json: positions | |
end | |
def create | |
position = Position.new( | |
position_params( | |
:lat, | |
:long, | |
:alt, | |
:time, | |
:prev_pos, | |
:next_pos, | |
:device_id | |
) | |
) | |
position.prev_pos = Position.where(device_id: device_id).order(time: :desc).first.id | |
if position.save | |
update_last_pos(position) | |
render json: position | |
else | |
render json: [{}], status: 404 | |
end | |
end | |
private | |
def position_params(*args) | |
params.require(:position).permit(*args) | |
end | |
def update_last_pos(current_pos) | |
last_pos = Position.where(device_id: device_id).order(time: :desc).second | |
last_pos.next_pos = current_pos.id | |
last_pos.save | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The gist of what I was trying to do
Basically, this is taken from the back end of a Rails API geolocation service that allows for a client (a device) to post its (current or cached) position to a database (using ActiveRecord).
What the code does
Starting from the top, the
PositionsController
is invoked when the Rails router receives a request from a route pointing to it (with a particular associated action invoking a method in the controller, e.g.#create
). As thePositionsController
inherits from theApplicationController
, it has access to the (hopefully self-explanatory) methods contained therein of#authorize_device!
and#device_id
(which returns the id of the device associated with the position as ascertained by its decoded security token1).The
#index
method merely returns an ActiveRecord object (resembling an array), listing out positions in reverse chronological order (by the position's:time
parameter).The
#create
method accepts a position post from a device, validates its parameters1, links it to the previous positional post from the same device (and vice-versa)2, and attempts to save it. If the save is successful and the position is persisted to the database, the position is rendered back to the client injson
format.1 Security
The device is assigned a JWT token after it signs in and must pass it along in its headers with each POST request to authenticate it (see: the
before_action :authorize_device!
on line 2). Position parameters are validated before Ruby objects are instantiated from them via the#position_params
method to prevent injection of unpermitted, possibly malicious parameters.2 Data structures
The position posts contain information about latitude, longitude, altitude, time3, and the database id of the device to which they belong as well as the database ids of the (chronologically) previous and next (
null
for the most recent) positions; these last parameters make positions a doubly-linked list for convenient traversal of the position chain, e.g. for the purposes of plotting routes on a map. A bonus feature to improve lookup times for large sets of time-bound positional search results could be realized by storing these positions in a balanced (e.g. red-black or AVL) binary search tree, which allows for lookup inO(log n)
time instead of theO(n)
time associated with traversing a list.3 Time
Time of GPS reading, which differs from the time of insertion into the database due to: