Class: Remotely::Model

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming, HTTPMethods
Includes:
ActiveModel::Conversion, Associations
Defined in:
lib/remotely/model.rb

Constant Summary

Constants included from HTTPMethods

HTTPMethods::SUCCESS_STATUSES

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes included from HTTPMethods

#app, #uri

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HTTPMethods

before_request, expand, get, http_delete, parse_response, post, put, raise_if_html

Methods included from Associations

included, #path_to, #remote_associations

Constructor Details

#initialize(attributes = {}) ⇒ Model

Returns a new instance of Model.



155
156
157
158
159
# File 'lib/remotely/model.rb', line 155

def initialize(attributes={})
  set_errors(attributes.delete('errors')) if attributes['errors']
  self.attributes = attributes.symbolize_keys
  associate!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object (private)



297
298
299
300
301
302
303
304
305
306
307
# File 'lib/remotely/model.rb', line 297

def method_missing(name, *args, &block)
  if self.attributes.include?(name) || self.savable_attributes.include?(name)
    self.attributes[name]
  elsif name =~ /(.*)=$/ && self.attributes.include?($1.to_sym)
    self.attributes[$1.to_sym] = args.first
  elsif name =~ /(.*)\?$/ && self.attributes.include?($1.to_sym)
    !!self.attributes[$1.to_sym]
  else
    super
  end
end

Class Attribute Details

.savable_attributesObject (readonly)

Array of attributes to be sent when saving



11
12
13
# File 'lib/remotely/model.rb', line 11

def savable_attributes
  @savable_attributes
end

Instance Attribute Details

#attributesHash

Returns Key-value of attributes and values.

Returns:

  • Key-value of attributes and values.



153
154
155
# File 'lib/remotely/model.rb', line 153

def attributes
  @attributes
end

Class Method Details

.allRemotely::Collection

Fetch all entries.

Returns:

  • collection of entries



31
32
33
# File 'lib/remotely/model.rb', line 31

def all
  get uri
end

.attr_savable(*attrs) ⇒ Object

Mark an attribute as safe to save. The save method will only send these attributes when called.

Examples:

Mark name and age as savable

attr_savable :name, :age

Parameters:

  • List of attributes to make savable.



21
22
23
24
25
# File 'lib/remotely/model.rb', line 21

def attr_savable(*attrs)
  @savable_attributes ||= []
  @savable_attributes += attrs
  @savable_attributes.uniq!
end

.base_classObject

Remotely models don’t support single table inheritence so the base class is always itself.



127
128
129
# File 'lib/remotely/model.rb', line 127

def base_class
  self
end

.create(params = {}) ⇒ Remotely::Model, Boolean Also known as: create!

Creates a new resource.

Parameters:

  • (defaults to: {})

    Attributes to create the new resource with.

Returns:

  • If the creation succeeds, a new model object is returned, otherwise false.



95
96
97
# File 'lib/remotely/model.rb', line 95

def create(params={})
  new(params).tap { |n| n.save }
end

.destroy(id) ⇒ Boolean

Destroy an individual resource.

Parameters:

  • id of the resource to destroy.

Returns:

  • If the destruction succeeded.



118
119
120
# File 'lib/remotely/model.rb', line 118

def destroy(id)
  http_delete URL(uri, id)
end

.destroy!Boolean

Destroy an individual resource.

Parameters:

  • id of the resource to destroy.

Returns:

  • If the destruction succeeded.



122
123
124
# File 'lib/remotely/model.rb', line 122

def destroy(id)
  http_delete URL(uri, id)
end

.find(id) ⇒ Remotely::Model

Retreive a single object. Combines uri and id to determine the URI to use.

Examples:

Find the User with id=1

User.find(1)

Parameters:

  • The id of the resource.

Returns:

  • Single model object.



45
46
47
# File 'lib/remotely/model.rb', line 45

def find(id)
  get URL(uri, id)
end

.find_or_create(attrs = {}) ⇒ Remotely::Model

Fetch the first record matching attrs or initialize and save a new instance with those attributes.

Parameters:

  • (defaults to: {})

    Attributes to search by, and subsequently instantiate and save with, if not found.

Returns:

  • Fetched or initialized model object



69
70
71
# File 'lib/remotely/model.rb', line 69

def find_or_create(attrs={})
  where(attrs).first or create(attrs)
end

.find_or_initialize(attrs = {}) ⇒ Remotely::Model

Fetch the first record matching attrs or initialize a new instance with those attributes.

Parameters:

  • (defaults to: {})

    Attributes to search by, and subsequently instantiate with, if not found.

Returns:

  • Fetched or initialized model object



57
58
59
# File 'lib/remotely/model.rb', line 57

def find_or_initialize(attrs={})
  where(attrs).first or new(attrs)
end

.update_all(params = {}) ⇒ Boolean Also known as: update_all!

Update every entry with values from params.

Parameters:

  • (defaults to: {})

    Key-Value pairs of attributes to update

Returns:

  • If the update succeeded



106
107
108
# File 'lib/remotely/model.rb', line 106

def update_all(params={})
  put uri, params
end

.where(params = {}) ⇒ Remotely::Collection

Search the remote API for a resource matching conditions specified in params. Sends params as a url-encoded query string. It assumes the search endpoint is at “/resource_plural/search”.

Examples:

Search for a person by name and title

User.where(:name => "Finn", :title => "The Human")

Parameters:

  • (defaults to: {})

    Key-value pairs of attributes and values to search by.

Returns:

  • Array-like collection of model objects.



84
85
86
# File 'lib/remotely/model.rb', line 84

def where(params={})
  get URL(uri, "search"), params
end

Instance Method Details

#destroyObject

Destroy this object with the might of 60 jotun!



240
241
242
# File 'lib/remotely/model.rb', line 240

def destroy
  self.class.destroy(id)
end

#errorsObject

Track errors with ActiveModel::Errors



234
235
236
# File 'lib/remotely/model.rb', line 234

def errors
  @errors ||= ActiveModel::Errors.new(self)
end

#idObject



251
252
253
# File 'lib/remotely/model.rb', line 251

def id
  self.attributes[:id]
end

#new_record?Boolean

Assumes that if the object doesn’t have an id, it’s new.

Returns:



257
258
259
# File 'lib/remotely/model.rb', line 257

def new_record?
  self.attributes[:id].nil?
end

#persisted?Boolean

Returns:



261
262
263
# File 'lib/remotely/model.rb', line 261

def persisted?
  !new_record?
end

#reloadObject

Re-fetch the resource from the remote API.



246
247
248
249
# File 'lib/remotely/model.rb', line 246

def reload
  self.attributes = get(URL(uri, id)).attributes
  self
end

#respond_to?(name) ⇒ Boolean

Returns:



265
266
267
# File 'lib/remotely/model.rb', line 265

def respond_to?(name)
  self.attributes and self.attributes.include?(name) or super
end

#savable_attributesObject



222
223
224
# File 'lib/remotely/model.rb', line 222

def savable_attributes
  self.class.savable_attributes || attributes.keys
end

#saveBoolean

Persist this object to the remote API.

If the request returns a status code of 201 or 200 (for creating new records and updating existing ones, respectively) it is considered a successful save and returns the object. Any other status will result in a return value of false. In addition, the obj.errors collection will be populated with any errors returns from the remote API.

For save to handle errors correctly, the remote API should return a response body which matches a JSONified ActiveRecord errors object. ie:

{"errors":{"attribute":["message", "message"]}}

Returns:

  • Remote API returns 200/201 status: true Remote API returns any other status: false



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/remotely/model.rb', line 204

def save
  method = new_record? ? :post      : :put
  status = new_record? ? 201        : 200
  attrs  = new_record? ? attributes : attributes.slice(*savable_attributes << :id)
  url    = new_record? ? uri        : URL(uri, id)

  resp = public_send(method, url, attrs)
  body = MultiJson.load(resp.body)

  if resp.status == status && !body.nil?
    self.attributes.merge!(body.symbolize_keys)
    true
  else
    set_errors(body.delete("errors")) unless body.nil?
    false
  end
end

#set_errors(hash) ⇒ Object

Sets multiple errors with a hash



227
228
229
230
231
# File 'lib/remotely/model.rb', line 227

def set_errors(hash)
  (hash || {}).each do |attribute, messages|
    Array(messages).each {|m| errors.add(attribute, m) }
  end
end

#to_jsonObject



269
270
271
# File 'lib/remotely/model.rb', line 269

def to_json
  MultiJson.dump(self.attributes)
end

#update_attribute(name, value) ⇒ Boolean, Mixed

Update a single attribute.

Parameters:

  • Attribute name

  • New value for the attribute

  • Should it save after updating the attributes. Default: true

Returns:

  • Boolean if the it tried to save, the new value otherwise.



170
171
172
173
# File 'lib/remotely/model.rb', line 170

def update_attribute(name, value)
  self.attributes[name.to_sym] = value
  save
end

#update_attributes(attrs = {}) ⇒ Boolean

Update multiple attributes.

Parameters:

  • (defaults to: {})

    Hash of attributes/values to update with.

Returns:

  • Did the save succeed.



180
181
182
183
# File 'lib/remotely/model.rb', line 180

def update_attributes(attrs={})
  self.attributes.merge!(attrs.symbolize_keys)
  save
end