Class: Remotely::Model

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming, Forwardable, 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.



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

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)



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

def method_missing(name, *args, &block)
  if self.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



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

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.



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

def attributes
  @attributes
end

Class Method Details

.allRemotely::Collection

Fetch all entries.

Returns:



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

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.



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

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.



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

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.



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

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.



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

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.



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

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:



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

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:



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

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:



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

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



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

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:



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

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

Instance Method Details

#destroyObject

Destroy this object with the might of 60 jotun!



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

def destroy
  self.class.destroy(id)
end

#errorsObject

Track errors with ActiveModel::Errors



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

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

#idObject



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

def id
  self.attributes[:id]
end

#new_record?Boolean

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

Returns:

  • (Boolean)


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

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

#persisted?Boolean

Returns:

  • (Boolean)


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

def persisted?
  !new_record?
end

#reloadObject

Re-fetch the resource from the remote API.



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

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

#respond_to?(name) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#savable_attributesObject



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

def savable_attributes
  (self.class.savable_attributes || attributes.keys) << :id
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



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

def save
  method = new_record? ? :post      : :put
  status = new_record? ? 201        : 200
  attrs  = new_record? ? attributes : attributes.slice(*savable_attributes)
  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



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

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

#to_jsonObject



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

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.



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

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.



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

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