-
Notifications
You must be signed in to change notification settings - Fork 18
How an object is updated
Let's take our favorite class again, Widget:
class Widget
include Arkenstone::Document
url 'http://example.com/widgets'
attributes :name, :size, :sku
end
widg = Widget.find 100 # Get's (Read up on the basics if you're unfamiliar with that code block.)
You can see what happens when you call Widget.find over in "How an object is retrieved"
There are a couple of ways to modify a Widget:
# First Way
widg.sku = '99999'
widg.save
# Second
widg.update_attribute 'sku', '99999'
# OMG Third
widg.update_attributes sku: '99999'Both of the update_attribute methods do the same thing: update the object's attributes, then call save.
save is in lib/arkenstone/document.rb within the Arkenstone::Document::InstanceMethods module.
At a high level, save take's an instance's attributes, creates a JSON object and sends it in a request to the url defined for the class.
First, check_for_url is called. This throws an exception if a url has not been declared for this class. Since we defined it up top, it'll pass.
If the class includes the Arkenstone::Timestamps module, the updated_at property is set to the current time.
Next, new_record? is called to see if this is a new object or one that was previously retrieved. We're focusing on updating, so the next call is to put_document_data.
put_document_data is in lib/arkenstone/document.rb within the Arkenstone::Document::InstanceMethods module.
All it does is call http_response and pass in the instance_url (this'll be http://example.com/widgets/100 in this case), and the PUT verb. If this were a brand new object, post_document_data would be called, which is similar, except uses a different url and the POST verb.
http_response is in lib/arkenstone/document.rb within the Arkenstone::Document::InstanceMethods module.
This method tells the Network module to send a request to the server, then handles the response that is returned.
This is another class method that is stored in lib/arkenstone/network/network.rb within the Arkenstone::Network::ClassMethods module. The third parameter, data, is optional, but since we are sending data to the server, we'll use it. data should be a Hash, and will be put into the request's body.
The first thing send_request does is construct an Arkenstone::Environment object.
Arkenstone relies on the net/http library to perform network requests. The request object does not lend itself very well to modification once it has been created, so we've created this Environment class in order to allow more customization before creating the request itself.
Arkenstone::Environment is stored in lib/arkenstone/network/env.rb. It encapsulates the url, verb, request body, and headers of a network request. These can be modified via hooks.
The constructor sets properties, and then we're back in send_request.
Speaking of hooks, all of the before_request hooks are called at this point. These can modify the Environment object in order to perform encoding or sanitization logic.
Next, the global Arkenstone::Network.send_request is called with the Environment object.
This is where the actual network request is made. A Net::HTTP object is constructed with properties from the env parameter.
Next, the appropriate request is created based on the HTTP Verb in the env parameter. Since we are updating an object, PUT is used. We end up with a Net::HTTP::Get object.
Our object information is stored in the env.body property and copied into the request body.
HTTP Headers are set next. Any headers defined in the env are added to the request.
Finally the request is made and returned back to the other send_request.
At this point the request has been sent and returned. Time to deal with the response. Which is what handle_response does.
If the request was successful (as determined by Arkenstone::Network.response_is_success), response hooks are called. If there was an error on the server, error hooks are called.
The response is returned and we are back in the http_response method.
If there was an error on the server, the arkenstone_server_errors property is populated with any error data kept in the response body.
In either case, the response object is returned, and is bubbled up back to save
The response body is parsed via the JSON parser to a ruby hash. The hash is then sent to the attributes= method.
This sets the values of multiple properties on the instance. Discards properties in the options that don't exist on the instance.
Back in save, a boolean is returned for whether the response from the server was successful.