MotionModelResource: Simple JSON API Wrapper for MotionModel on RubyMotion

MotionModelResource is a simple wrapper to store your remote data in MotionModel objects. It is good for users who have a REST API and want to have it in an iOS app.

You need to have MotionModel ready, if you want to use this implementation: https://github.com/sxross/MotionModel

Overview

Installation

Add the following line to your Gemfile:

gem "motion_model_resource"

You need to require the Gem. Insert the following immediately before Motion::Project::App.setup:

require 'motion_model' # If you haven't already
require 'motion_model_resource'

Then, update your bundle:

bundle

Setup

First of all you will need a normal MotionModel::Model:

class Task
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter

  columns name:         :string,
          long_name:    :string,
          due_date:     :date,
          lastSyncedAt: :time
end

Tune this up, by adding:

...
  include MotionModelResource::ApiWrapper

  def self.url
    "https://example.com/tasks"
  end

  def self.wrapper
    @wrapper ||= {
      fields: {
        id:         :id,
        name:       :name,
        long_name:  :long_name,
        due_date:   :due_date
      },
      relations: [:user]
    }
  end
...

The wrapper hash has two main keys. The first one is "fields". Here you specify the local and remote keys, you want to have from your API response. The hash-key is the remote key and the hash-value is the local key. It is used, if you have different names in your implementation (maybe camelcase with underscore). The second key in the main hash is the "relations" part. Here you can specify the wanted relations from your remote response. It will automatacally look after the right relation, for example if you have a relation "tasks", and the response is an array, it will create a bunch of tasks for you.

The url method will be used for saving a remote model. Maybe in future for a routes prefix.

Usage

Getting Remote Models

Fetching your API by calling "fetch" on your model class:

Task.fetch("https://example.com/tasks")

Example Response

[{
  "id": 1,
  "name": 'Buy beer',
  "long_name": 'Many, many, many beer!',
  "due_date": "2013-11-03T20:40:00+01:00",
  "updated_at": "2013-11-03T20:20:10+01:00",
  "created_at": "2013-11-03T20:06:01+01:00"
},{
  "id": 2,
  "name": 'Drink beer',
  "long_name": 'Beer, beer, beer, beer',
  "due_date": "2013-11-03T21:40:00+01:00",
  "updated_at": "2013-11-03T20:20:10+01:00",
  "created_at": "2013-11-03T20266:01+01:00"
}]

After this call, you will have a bunch of records in your collection. If you want to have a direct callback, after the new records have stored, you can call the method with a block:

Task.fetch("https://example.com/tasks") do |tasks|
  tasks.each do |task|
    puts task.name
  end
end

If you need specific URL parameters, you can add them as the second parameter:

Task.fetch("https://example.com/tasks", {api_key: "top_secret!"})

If you want to update an existing record, you can use the instance method fetch.

task = Task.first
task.fetch("https://example.com/tasks")

Tip: If you have the lastSyncedAt column in your model, this will automatacally set to the current timestamp!

Saving Remote Models

If you want to store your local model, you can simply do this with MotionModelResource. You just need to configure an url class method and giving a block for the save method:

task = Task.first
task.name = "Drinking a lot of soda"
task.save do |model|
  if model.present?
    puts "task saved!"
  else
    puts "Damn, something went wrong..."
  end
end

The task object will update, too. As you can see, if the model var is nil, the save process had failed. The save method will store the relations too!! It will serialize the whole model and push this to the server. The mapping information comes also from the wrapper method.