activeresource 5.0.0 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/MIT-LICENSE +20 -0
- data/README.rdoc +48 -10
- data/lib/active_resource/active_job_serializer.rb +26 -0
- data/lib/active_resource/associations/builder/association.rb +5 -4
- data/lib/active_resource/associations/builder/belongs_to.rb +4 -2
- data/lib/active_resource/associations/builder/has_many.rb +3 -1
- data/lib/active_resource/associations/builder/has_one.rb +4 -2
- data/lib/active_resource/associations.rb +10 -10
- data/lib/active_resource/base.rb +142 -77
- data/lib/active_resource/callbacks.rb +3 -1
- data/lib/active_resource/collection.rb +5 -3
- data/lib/active_resource/connection.rb +70 -75
- data/lib/active_resource/custom_methods.rb +8 -6
- data/lib/active_resource/exceptions.rb +5 -3
- data/lib/active_resource/formats/json_format.rb +4 -1
- data/lib/active_resource/formats/xml_format.rb +4 -2
- data/lib/active_resource/formats.rb +4 -2
- data/lib/active_resource/http_mock.rb +18 -20
- data/lib/active_resource/log_subscriber.rb +14 -3
- data/lib/active_resource/railtie.rb +13 -3
- data/lib/active_resource/reflection.rb +10 -9
- data/lib/active_resource/schema.rb +5 -3
- data/lib/active_resource/singleton.rb +25 -26
- data/lib/active_resource/threadsafe_attributes.rb +30 -29
- data/lib/active_resource/validations.rb +12 -10
- data/lib/active_resource/version.rb +5 -3
- data/lib/active_resource.rb +7 -5
- data/lib/activeresource.rb +3 -1
- metadata +9 -8
data/lib/active_resource/base.rb
CHANGED
@@ -1,26 +1,28 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
|
14
|
-
require
|
15
|
-
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
|
23
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support"
|
4
|
+
require "active_support/core_ext/class/attribute_accessors"
|
5
|
+
require "active_support/core_ext/class/attribute"
|
6
|
+
require "active_support/core_ext/hash/indifferent_access"
|
7
|
+
require "active_support/core_ext/kernel/reporting"
|
8
|
+
require "active_support/core_ext/module/delegation"
|
9
|
+
require "active_support/core_ext/module/aliasing"
|
10
|
+
require "active_support/core_ext/object/blank"
|
11
|
+
require "active_support/core_ext/object/to_query"
|
12
|
+
require "active_support/core_ext/object/duplicable"
|
13
|
+
require "set"
|
14
|
+
require "uri"
|
15
|
+
|
16
|
+
require "active_support/core_ext/uri"
|
17
|
+
require "active_resource/connection"
|
18
|
+
require "active_resource/formats"
|
19
|
+
require "active_resource/schema"
|
20
|
+
require "active_resource/log_subscriber"
|
21
|
+
require "active_resource/associations"
|
22
|
+
require "active_resource/reflection"
|
23
|
+
require "active_resource/threadsafe_attributes"
|
24
|
+
|
25
|
+
require "active_model/serializers/xml"
|
24
26
|
|
25
27
|
module ActiveResource
|
26
28
|
# ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application.
|
@@ -300,7 +302,12 @@ module ActiveResource
|
|
300
302
|
##
|
301
303
|
# :singleton-method:
|
302
304
|
# The logger for diagnosing and tracing Active Resource calls.
|
303
|
-
|
305
|
+
cattr_reader :logger
|
306
|
+
|
307
|
+
def self.logger=(logger)
|
308
|
+
self._connection = nil
|
309
|
+
@@logger = logger
|
310
|
+
end
|
304
311
|
|
305
312
|
class_attribute :_format
|
306
313
|
class_attribute :_collection_parser
|
@@ -378,7 +385,7 @@ module ActiveResource
|
|
378
385
|
@schema ||= {}.with_indifferent_access
|
379
386
|
@known_attributes ||= []
|
380
387
|
|
381
|
-
schema_definition.attrs.each do |k,v|
|
388
|
+
schema_definition.attrs.each do |k, v|
|
382
389
|
@schema[k] = v
|
383
390
|
@known_attributes << k
|
384
391
|
end
|
@@ -417,7 +424,7 @@ module ActiveResource
|
|
417
424
|
raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash
|
418
425
|
|
419
426
|
schema do
|
420
|
-
the_schema.each {|k,v| attribute(k,v) }
|
427
|
+
the_schema.each { |k, v| attribute(k, v) }
|
421
428
|
end
|
422
429
|
end
|
423
430
|
|
@@ -619,7 +626,7 @@ module ActiveResource
|
|
619
626
|
# * <tt>:ssl_timeout</tt> -The SSL timeout in seconds.
|
620
627
|
def ssl_options=(options)
|
621
628
|
self._connection = nil
|
622
|
-
@ssl_options
|
629
|
+
@ssl_options = options
|
623
630
|
end
|
624
631
|
|
625
632
|
# Returns the SSL options hash.
|
@@ -636,7 +643,9 @@ module ActiveResource
|
|
636
643
|
# or not (defaults to <tt>false</tt>).
|
637
644
|
def connection(refresh = false)
|
638
645
|
if _connection_defined? || superclass == Object
|
639
|
-
self._connection = connection_class.new(
|
646
|
+
self._connection = connection_class.new(
|
647
|
+
site, format, logger: logger
|
648
|
+
) if refresh || _connection.nil?
|
640
649
|
_connection.proxy = proxy if proxy
|
641
650
|
_connection.user = user if user
|
642
651
|
_connection.password = password if password
|
@@ -682,15 +691,15 @@ module ActiveResource
|
|
682
691
|
return primary_key if primary_key.is_a?(Symbol)
|
683
692
|
primary_key.dup.freeze
|
684
693
|
else
|
685
|
-
|
694
|
+
"id"
|
686
695
|
end
|
687
696
|
end
|
688
697
|
|
689
698
|
# Gets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.json</tt>)
|
690
699
|
# This method is regenerated at runtime based on what the \prefix is set to.
|
691
|
-
def prefix(options={})
|
700
|
+
def prefix(options = {})
|
692
701
|
default = site.path
|
693
|
-
default <<
|
702
|
+
default << "/" unless default[-1..-1] == "/"
|
694
703
|
# generate the actual method based on the current site path
|
695
704
|
self.prefix = default
|
696
705
|
prefix(options)
|
@@ -705,7 +714,7 @@ module ActiveResource
|
|
705
714
|
|
706
715
|
# Sets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.json</tt>).
|
707
716
|
# Default value is <tt>site.path</tt>.
|
708
|
-
def prefix=(value =
|
717
|
+
def prefix=(value = "/")
|
709
718
|
# Replace :placeholders with '#{embedded options[:lookups]}'
|
710
719
|
prefix_call = value.gsub(/:\w+/) { |key| "\#{URI.parser.escape options[#{key}].to_s}" }
|
711
720
|
|
@@ -763,7 +772,37 @@ module ActiveResource
|
|
763
772
|
check_prefix_options(prefix_options)
|
764
773
|
|
765
774
|
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
766
|
-
"#{prefix(prefix_options)}#{collection_name}/#{URI.
|
775
|
+
"#{prefix(prefix_options)}#{collection_name}/#{URI.encode_www_form_component(id.to_s)}#{format_extension}#{query_string(query_options)}"
|
776
|
+
end
|
777
|
+
|
778
|
+
# Gets the element url for the given ID in +id+. If the +query_options+ parameter is omitted, Rails
|
779
|
+
# will split from the \prefix options.
|
780
|
+
#
|
781
|
+
# ==== Options
|
782
|
+
# +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
|
783
|
+
# would yield a URL like <tt>https://37s.sunrise.com/accounts/19/purchases.json</tt>).
|
784
|
+
#
|
785
|
+
# +query_options+ - A \hash to add items to the query string for the request.
|
786
|
+
#
|
787
|
+
# ==== Examples
|
788
|
+
# Post.element_url(1)
|
789
|
+
# # => https://37s.sunrise.com/posts/1.json
|
790
|
+
#
|
791
|
+
# class Comment < ActiveResource::Base
|
792
|
+
# self.site = "https://37s.sunrise.com/posts/:post_id"
|
793
|
+
# end
|
794
|
+
#
|
795
|
+
# Comment.element_url(1, :post_id => 5)
|
796
|
+
# # => https://37s.sunrise.com/posts/5/comments/1.json
|
797
|
+
#
|
798
|
+
# Comment.element_url(1, :post_id => 5, :active => 1)
|
799
|
+
# # => https://37s.sunrise.com/posts/5/comments/1.json?active=1
|
800
|
+
#
|
801
|
+
# Comment.element_url(1, {:post_id => 5}, {:active => 1})
|
802
|
+
# # => https://37s.sunrise.com/posts/5/comments/1.json?active=1
|
803
|
+
#
|
804
|
+
def element_url(id, prefix_options = {}, query_options = nil)
|
805
|
+
URI.join(site, element_path(id, prefix_options, query_options)).to_s
|
767
806
|
end
|
768
807
|
|
769
808
|
# Gets the new element path for REST resources.
|
@@ -931,11 +970,18 @@ module ActiveResource
|
|
931
970
|
options = arguments.slice!(0) || {}
|
932
971
|
|
933
972
|
case scope
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
973
|
+
when :all
|
974
|
+
find_every(options)
|
975
|
+
when :first
|
976
|
+
collection = find_every(options)
|
977
|
+
collection && collection.first
|
978
|
+
when :last
|
979
|
+
collection = find_every(options)
|
980
|
+
collection && collection.last
|
981
|
+
when :one
|
982
|
+
find_one(options)
|
983
|
+
else
|
984
|
+
find_single(scope, options)
|
939
985
|
end
|
940
986
|
end
|
941
987
|
|
@@ -962,7 +1008,7 @@ module ActiveResource
|
|
962
1008
|
|
963
1009
|
def where(clauses = {})
|
964
1010
|
raise ArgumentError, "expected a clauses Hash, got #{clauses.inspect}" unless clauses.is_a? Hash
|
965
|
-
find(:all, :
|
1011
|
+
find(:all, params: clauses)
|
966
1012
|
end
|
967
1013
|
|
968
1014
|
|
@@ -996,7 +1042,7 @@ module ActiveResource
|
|
996
1042
|
prefix_options, query_options = split_options(options[:params])
|
997
1043
|
path = element_path(id, prefix_options, query_options)
|
998
1044
|
response = connection.head(path, headers)
|
999
|
-
(200..206).include? response.code
|
1045
|
+
(200..206).include? response.code.to_i
|
1000
1046
|
end
|
1001
1047
|
# id && !find_single(id, options).nil?
|
1002
1048
|
rescue ActiveResource::ResourceNotFound, ActiveResource::ResourceGone
|
@@ -1024,7 +1070,7 @@ module ActiveResource
|
|
1024
1070
|
else
|
1025
1071
|
prefix_options, query_options = split_options(options[:params])
|
1026
1072
|
path = collection_path(prefix_options, query_options)
|
1027
|
-
instantiate_collection(
|
1073
|
+
instantiate_collection((format.decode(connection.get(path, headers).body) || []), query_options, prefix_options)
|
1028
1074
|
end
|
1029
1075
|
rescue ActiveResource::ResourceNotFound
|
1030
1076
|
# Swallowing ResourceNotFound exceptions and return nil - as per
|
@@ -1091,8 +1137,8 @@ module ActiveResource
|
|
1091
1137
|
prefix_options, query_options = {}, {}
|
1092
1138
|
|
1093
1139
|
(options || {}).each do |key, value|
|
1094
|
-
next if key.blank?
|
1095
|
-
(prefix_parameters.include?(key.to_sym) ? prefix_options : query_options)[key.to_sym] = value
|
1140
|
+
next if key.blank?
|
1141
|
+
(prefix_parameters.include?(key.to_s.to_sym) ? prefix_options : query_options)[key.to_s.to_sym] = value
|
1096
1142
|
end
|
1097
1143
|
|
1098
1144
|
[ prefix_options, query_options ]
|
@@ -1157,13 +1203,13 @@ module ActiveResource
|
|
1157
1203
|
# not_ryan.hash # => {:not => "an ARes instance"}
|
1158
1204
|
def clone
|
1159
1205
|
# Clone all attributes except the pk and any nested ARes
|
1160
|
-
cloned = Hash[attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.map { |k, v| [k, v.clone] }]
|
1206
|
+
cloned = Hash[attributes.reject { |k, v| k == self.class.primary_key || v.is_a?(ActiveResource::Base) }.map { |k, v| [k, v.clone] }]
|
1161
1207
|
# Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
|
1162
1208
|
# attempts to convert hashes into member objects and arrays into collections of objects. We want
|
1163
1209
|
# the raw objects to be cloned so we bypass load by directly setting the attributes hash.
|
1164
1210
|
resource = self.class.new({})
|
1165
1211
|
resource.prefix_options = self.prefix_options
|
1166
|
-
resource.send :instance_variable_set,
|
1212
|
+
resource.send :instance_variable_set, "@attributes", cloned
|
1167
1213
|
resource
|
1168
1214
|
end
|
1169
1215
|
|
@@ -1338,13 +1384,13 @@ module ActiveResource
|
|
1338
1384
|
# Person.delete(guys_id)
|
1339
1385
|
# that_guy.exists? # => false
|
1340
1386
|
def exists?
|
1341
|
-
!new? && self.class.exists?(to_param, :
|
1387
|
+
!new? && self.class.exists?(to_param, params: prefix_options)
|
1342
1388
|
end
|
1343
1389
|
|
1344
1390
|
# Returns the serialized string representation of the resource in the configured
|
1345
1391
|
# serialization format specified in ActiveResource::Base.format. The options
|
1346
1392
|
# applicable depend on the configured encoding format.
|
1347
|
-
def encode(options={})
|
1393
|
+
def encode(options = {})
|
1348
1394
|
send("to_#{self.class.format.extension}", options)
|
1349
1395
|
end
|
1350
1396
|
|
@@ -1360,7 +1406,7 @@ module ActiveResource
|
|
1360
1406
|
# my_branch.reload
|
1361
1407
|
# my_branch.name # => "Wilson Road"
|
1362
1408
|
def reload
|
1363
|
-
self.load(self.class.find(to_param, :
|
1409
|
+
self.load(self.class.find(to_param, params: @prefix_options).attributes, false, true)
|
1364
1410
|
end
|
1365
1411
|
|
1366
1412
|
# A method to manually load attributes from a \hash. Recursively loads collections of
|
@@ -1401,21 +1447,21 @@ module ActiveResource
|
|
1401
1447
|
attributes.each do |key, value|
|
1402
1448
|
@attributes[key.to_s] =
|
1403
1449
|
case value
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
end
|
1450
|
+
when Array
|
1451
|
+
resource = nil
|
1452
|
+
value.map do |attrs|
|
1453
|
+
if attrs.is_a?(Hash)
|
1454
|
+
resource ||= find_or_create_resource_for_collection(key)
|
1455
|
+
resource.new(attrs, persisted)
|
1456
|
+
else
|
1457
|
+
attrs.duplicable? ? attrs.dup : attrs
|
1413
1458
|
end
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1459
|
+
end
|
1460
|
+
when Hash
|
1461
|
+
resource = find_or_create_resource_for(key)
|
1462
|
+
resource.new(value, persisted)
|
1463
|
+
else
|
1464
|
+
value.duplicable? ? value.dup : value
|
1419
1465
|
end
|
1420
1466
|
end
|
1421
1467
|
self
|
@@ -1472,12 +1518,20 @@ module ActiveResource
|
|
1472
1518
|
end
|
1473
1519
|
end
|
1474
1520
|
|
1475
|
-
def to_json(options={})
|
1476
|
-
super(include_root_in_json ? { :
|
1521
|
+
def to_json(options = {})
|
1522
|
+
super(include_root_in_json ? { root: self.class.element_name }.merge(options) : options)
|
1477
1523
|
end
|
1478
1524
|
|
1479
|
-
def to_xml(options={})
|
1480
|
-
super({ :
|
1525
|
+
def to_xml(options = {})
|
1526
|
+
super({ root: self.class.element_name }.merge(options))
|
1527
|
+
end
|
1528
|
+
|
1529
|
+
def read_attribute_for_serialization(n)
|
1530
|
+
if !attributes[n].nil?
|
1531
|
+
attributes[n]
|
1532
|
+
elsif respond_to?(n)
|
1533
|
+
send(n)
|
1534
|
+
end
|
1481
1535
|
end
|
1482
1536
|
|
1483
1537
|
protected
|
@@ -1505,9 +1559,9 @@ module ActiveResource
|
|
1505
1559
|
end
|
1506
1560
|
|
1507
1561
|
def load_attributes_from_response(response)
|
1508
|
-
if
|
1509
|
-
(response[
|
1510
|
-
!response.body.nil? && response.body.strip.size > 0
|
1562
|
+
if response_code_allows_body?(response.code.to_i) &&
|
1563
|
+
(response["Content-Length"].nil? || response["Content-Length"] != "0") &&
|
1564
|
+
!response.body.nil? && response.body.strip.size > 0
|
1511
1565
|
load(self.class.format.decode(response.body), true, true)
|
1512
1566
|
@persisted = true
|
1513
1567
|
end
|
@@ -1515,13 +1569,17 @@ module ActiveResource
|
|
1515
1569
|
|
1516
1570
|
# Takes a response from a typical create post and pulls the ID out
|
1517
1571
|
def id_from_response(response)
|
1518
|
-
response[
|
1572
|
+
response["Location"][/\/([^\/]*?)(\.\w+)?$/, 1] if response["Location"]
|
1519
1573
|
end
|
1520
1574
|
|
1521
1575
|
def element_path(options = nil)
|
1522
1576
|
self.class.element_path(to_param, options || prefix_options)
|
1523
1577
|
end
|
1524
1578
|
|
1579
|
+
def element_url(options = nil)
|
1580
|
+
self.class.element_url(to_param, options || prefix_options)
|
1581
|
+
end
|
1582
|
+
|
1525
1583
|
def new_element_path
|
1526
1584
|
self.class.new_element_path(prefix_options)
|
1527
1585
|
end
|
@@ -1532,13 +1590,9 @@ module ActiveResource
|
|
1532
1590
|
|
1533
1591
|
private
|
1534
1592
|
|
1535
|
-
def read_attribute_for_serialization(n)
|
1536
|
-
attributes[n]
|
1537
|
-
end
|
1538
|
-
|
1539
1593
|
# Determine whether the response is allowed to have a body per HTTP 1.1 spec section 4.4.1
|
1540
1594
|
def response_code_allows_body?(c)
|
1541
|
-
!((100..199).include?(c) || [204,304].include?(c))
|
1595
|
+
!((100..199).include?(c) || [204, 304].include?(c))
|
1542
1596
|
end
|
1543
1597
|
|
1544
1598
|
# Tries to find a resource for a given collection name; if it fails, then the resource is created
|
@@ -1551,7 +1605,7 @@ module ActiveResource
|
|
1551
1605
|
# if it fails, then the resource is created
|
1552
1606
|
def find_or_create_resource_in_modules(resource_name, module_names)
|
1553
1607
|
receiver = Object
|
1554
|
-
namespaces = module_names[0, module_names.size-1].map do |module_name|
|
1608
|
+
namespaces = module_names[0, module_names.size - 1].map do |module_name|
|
1555
1609
|
receiver = receiver.const_get(module_name)
|
1556
1610
|
end
|
1557
1611
|
const_args = [resource_name, false]
|
@@ -1568,7 +1622,11 @@ module ActiveResource
|
|
1568
1622
|
resource_name = name.to_s.camelize
|
1569
1623
|
|
1570
1624
|
const_args = [resource_name, false]
|
1571
|
-
|
1625
|
+
|
1626
|
+
if !const_valid?(*const_args)
|
1627
|
+
# resource_name is not a valid ruby module name and cannot be created normally
|
1628
|
+
find_or_create_resource_for(:UnnamedResource)
|
1629
|
+
elsif self.class.const_defined?(*const_args)
|
1572
1630
|
self.class.const_get(*const_args)
|
1573
1631
|
else
|
1574
1632
|
ancestors = self.class.name.to_s.split("::")
|
@@ -1584,6 +1642,13 @@ module ActiveResource
|
|
1584
1642
|
end
|
1585
1643
|
end
|
1586
1644
|
|
1645
|
+
def const_valid?(*const_args)
|
1646
|
+
self.class.const_defined?(*const_args)
|
1647
|
+
true
|
1648
|
+
rescue NameError
|
1649
|
+
false
|
1650
|
+
end
|
1651
|
+
|
1587
1652
|
# Create and return a class definition for a resource inside the current resource
|
1588
1653
|
def create_resource_for(resource_name)
|
1589
1654
|
resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base))
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/delegation"
|
4
|
+
require "active_support/inflector"
|
3
5
|
|
4
6
|
module ActiveResource # :nodoc:
|
5
7
|
class Collection # :nodoc:
|
6
8
|
SELF_DEFINE_METHODS = [:to_a, :collect!, :map!]
|
7
9
|
include Enumerable
|
8
|
-
delegate :to_yaml, :all?, *(Array.instance_methods(false) - SELF_DEFINE_METHODS), :
|
10
|
+
delegate :to_yaml, :all?, *(Array.instance_methods(false) - SELF_DEFINE_METHODS), to: :to_a
|
9
11
|
|
10
12
|
# The array of actual elements returned by index actions
|
11
13
|
attr_accessor :elements, :resource_class, :original_params
|