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:

  • (Hash)

    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:



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:

  • *attrs (Symbols)

    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:

  • params (Hash) (defaults to: {})

    Attributes to create the new resource with.

Returns:

  • (Remotely::Model, Boolean)

    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 (Fixnum)

    id of the resource to destroy.

Returns:

  • (Boolean)

    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 (Fixnum)

    id of the resource to destroy.

Returns:

  • (Boolean)

    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:

  • id (Fixnum)

    The ‘id` of the resource.

Returns:



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:

  • attrs (Hash) (defaults to: {})

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

Returns:



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:

  • attrs (Hash) (defaults to: {})

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

Returns:



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:

  • params (Hash) (defaults to: {})

    Key-Value pairs of attributes to update

Returns:

  • (Boolean)

    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:

  • params (Hash) (defaults to: {})

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

Returns:



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:

  • (Boolean)


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

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

#persisted?Boolean

Returns:

  • (Boolean)


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:

  • (Boolean)


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:

  • (Boolean)

    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:

  • name (Symbol, String)

    Attribute name

  • value (Mixed)

    New value for the attribute

  • should_save (Boolean)

    Should it save after updating the attributes. Default: true

Returns:

  • (Boolean, Mixed)

    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:

  • attrs (Hash) (defaults to: {})

    Hash of attributes/values to update with.

Returns:

  • (Boolean)

    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