-
Notifications
You must be signed in to change notification settings - Fork 359
/
Copy pathsingleton.rb
138 lines (124 loc) · 4.75 KB
/
singleton.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# frozen_string_literal: true
module ActiveResource
# === Custom REST methods
#
# Since simple CRUD/life cycle methods can't accomplish every task, Singleton Resources can also support
# defining custom REST methods. To invoke them, Active Resource provides the <tt>get</tt>,
# <tt>post</tt>, <tt>put</tt> and <tt>delete</tt> methods where you can specify a custom REST method
# name to invoke.
#
# Singleton resources use their <tt>singleton_name</tt> value as their default
# <tt>collection_name</tt> value when constructing the request's path.
#
# # GET to report on the Inventory, i.e. GET /products/1/inventory/report.json.
# Inventory.get(:report, product_id: 1)
# # => [{:count => 'Manager'}, {:name => 'Clerk'}]
#
# # DELETE to 'reset' an inventory, i.e. DELETE /products/1/inventory/reset.json.
# Inventory.find(params: { product_id: 1 }).delete(:reset)
#
# For more information on using custom REST methods, see the
# ActiveResource::CustomMethods documentation.
module Singleton
extend ActiveSupport::Concern
module ClassMethods
attr_writer :singleton_name
def singleton_name
@singleton_name ||= model_name.element
end
def collection_name
@collection_name ||= singleton_name
end
# Gets the singleton path for the object. If the +query_options+ parameter is omitted, Rails
# will split from the \prefix options.
#
# ==== Options
# * +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
# would yield a URL like <tt>/accounts/19/purchases.json</tt>).
#
# * +query_options+ - A \hash to add items to the query string for the request.
#
# ==== Examples
# Weather.singleton_path
# # => /weather.json
#
# class Inventory < ActiveResource::Base
# self.site = "https://37s.sunrise.com"
# self.prefix = "/products/:product_id/"
# end
#
# Inventory.singleton_path(:product_id => 5)
# # => /products/5/inventory.json
#
# Inventory.singleton_path({:product_id => 5}, {:sold => true})
# # => /products/5/inventory.json?sold=true
#
def singleton_path(prefix_options = {}, query_options = nil)
check_prefix_options(prefix_options)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{singleton_name}#{format_extension}#{query_string(query_options)}"
end
# Core method for finding singleton resources.
#
# ==== Arguments
# Takes a single argument of options
#
# ==== Options
# * <tt>:params</tt> - Sets the query and \prefix (nested URL) parameters.
#
# ==== Examples
# Weather.find
# # => GET /weather.json
#
# Weather.find(:params => {:degrees => 'fahrenheit'})
# # => GET /weather.json?degrees=fahrenheit
#
# == Failure or missing data
# A failure to find the requested object raises a ResourceNotFound exception.
#
# Inventory.find
# # => raises ResourceNotFound
def find(options = {})
find_singleton(options)
end
private
# Find singleton resource
def find_singleton(options)
prefix_options, query_options = split_options(options[:params])
path = singleton_path(prefix_options, query_options)
resp = self.format.decode(self.connection.get(path, self.headers).body)
instantiate_record(resp, prefix_options)
end
end
# Deletes the resource from the remote service.
#
# ==== Examples
# weather = Weather.find
# weather.destroy
# Weather.find # 404 (Resource Not Found)
def destroy
connection.delete(singleton_path, self.class.headers)
end
protected
# Update the resource on the remote service
def update
connection.put(singleton_path(prefix_options), encode, self.class.headers).tap do |response|
load_attributes_from_response(response)
end
end
# Create (i.e. \save to the remote service) the \new resource.
def create
connection.post(singleton_path, encode, self.class.headers).tap do |response|
self.id = id_from_response(response)
load_attributes_from_response(response)
end
end
private
def singleton_path(options = nil)
self.class.singleton_path(options || prefix_options)
end
def custom_method_element_url(method_name, options = {})
"#{self.class.prefix(prefix_options)}#{self.class.collection_name}/#{method_name}#{self.class.format_extension}#{self.class.__send__(:query_string, options)}"
end
end
end