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