Remotely lets you specify associations for your models that should be fetched from a remote API instead of the database.
Apps are where Remotely goes to find association resources. You can define as many as you want, but if you define only one, you can omit the :app
option from your associations. Remotely also supports any Faraday middleware, to configure just call use_middleware
with the class name and options.
Remotely.configure do
app :legsapp do
url "http://somanylegs.com/api/v1"
basic_auth "username", "password"
use_middleware Faraday::HttpCache, store: MyCache.new
end
end
class Millepied < Remotely::Model
app :legsapp
uri "/legs"
# Optional - restrict saveable attributes
attr_savable :name, :type
end
has_many_remote
takes two options, :app
and :path
. :app
tells Remotely which registered app to fetch it from. :path
tells it the URI to the object (everything after the app).
One app & association name matches URI
class Millepied < ActiveRecord::Base
has_many_remote :legs # => "/legs"
end
One app & custom path
class Millepied < ActiveRecord::Base
has_many_remote :legs, :path => "/store/legs"
end
One app & custom path with id
substitution
class Millepied < ActiveRecord::Base
has_many_remote :legs, :path => "/millepieds/:id/legs"
end
Multiple apps (all secondary conditions from above apply)
class Millepied < ActiveRecord::Base
has_many_remote :legs, :app => :legsapp, ...
end
Note about associations
If you do not specify the :app
options in your associations, you need
to create a Remotely::Model
subclass for the associated object. This
is so Remotely knows which app to use to retrieve entries of that type.
class Person < ActiveRecord::Base
has_many_remote :legs
end
# Means the following must exist:
class Leg < Remotely::Model
app :legsapp
uri "/legs"
end
A path can include ":id
" anywhere in it, which is replaced by the instance's id
. This is useful when the resource on the API end is namespaced. For example:
class Millepied < ActiveRecord::Base
has_many_remote :legs, :path => "/millepieds/:id/legs"
end
m = Millepied.new
m.id # => 1
m.legs # => Requests "/millepieds/1/legs"
Remotely is setup to allow basic auth, token auth, or custom authentication schemes.
Basic Auth
basic_auth
accepts 2 String params: username
and password
# 'Authorization' header => "Basic dXNlcjpwYXNzd29yZA=="
Remotely.configure do
app :legsapp do
url "http://somanylegs.com/api/v1"
basic_auth "username", "password"
end
end
Token Auth
token_auth
accepts a String param for the token
, and an optional Hash of token options
# 'Authorization' header => "Token token=\"abcdef\", foo=\"bar\""
Remotely.configure do
app :legsapp do
url "http://somanylegs.com/api/v1"
token_auth "abcdef", {:foo => 'bar'}
end
end
Custom Authorization
authorization
accepts a String param for the type
, and either a String or Hash token
. A String value is taken literally, and a Hash is encoded into comma separated key/value pairs.
# 'Authorization' header => "Bearer mF_9.B5f-4.1JqM"
Remotely.configure do
app :legsapp do
url "http://somanylegs.com/api/v1"
authorization 'Bearer', 'mF_9.B5f-4.1JqM'
end
end
# 'Authorization' header => "OAuth token=\"abcdef\", foo=\"bar\""
Remotely.configure do
app :legsapp do
url "http://somanylegs.com/api/v1"
authorization 'OAuth', {:token => 'abcdef', :foo => 'bar'}
end
end
Remote associations are Remotely::Model objects. Whatever data the API returns, becomes the attributes of the Model.
m = Millepied.new
m.legs[0] # => #<Remotely::Model:0x0000f351c8 @attributes={:length=>"1mm"}>
m.legs[0].length # => "1mm"
If a fetched object includes an attribute matching "*_id", Remotely tries to find the model it is for and retrieve it.
leg = m.legs.first
leg.user_id # => 2
leg.user # => User.find(2)
Fork, branch and pull-request. Bump versions in their own commit.