hal_api-rails 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 179cbb4fbac529e58ced08b20fb02ca82bf77bba
4
- data.tar.gz: 1218e1583824ce7f04f686edac03e68bc5e4fa54
3
+ metadata.gz: d5fd9d4857d9ce82ac91cae49c2b239e1ed4ebac
4
+ data.tar.gz: 9f19281381dbdfc58f76b942421c36a7531aacac
5
5
  SHA512:
6
- metadata.gz: 4396211e73d1d968b088a08d7f0d0d6d4ba74f267a2112897393299d94466d72c7e82d17dec1a0b872f59e4fee12913a48b812bfbb63280251cde0d4b98c6d12
7
- data.tar.gz: 32a4f303b627198c99a6d97bc21846dae4283431e08da917b027b85ad648c647e4acc8d4803df59aba8ee18847c9b1df6384fae28a0476900b3612b4ca37283e
6
+ metadata.gz: c8f2041c5eceda12f490af0169b5058ea32b9f782fddeb0c1bbf15ad19973fe2a08dc38f90956accf7557160393a24709e20744ecf53dd4b7fb18d9aee5d60d7
7
+ data.tar.gz: c6c89868387c3416b6ea2ca71114e46a13b33f9a20552a47fab404e31dac0bec96f8af99c97b0f02f4e59d1a072829e0541aa3acd17e0604ccd403a5e8124524
data/README.md CHANGED
@@ -24,7 +24,51 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
- TODO: Write usage instructions here
27
+ This gem provides a number of additions to the `roar` gem HAL support.
28
+
29
+ There are several parts of it that need to be used in your apps:
30
+
31
+ 1) Add to your API controllers:
32
+
33
+ ```ruby
34
+ require 'hal_api/rails'
35
+
36
+ class Api::BaseController < ApplicationController
37
+ include HalApi::Controller
38
+ ...
39
+ end
40
+ ```
41
+
42
+ 2) Add to your `ActiveRecord` models used in your API (perhaps in a base model class):
43
+ ```ruby
44
+ class BaseModel < ActiveRecord::Base
45
+ self.abstract_class = true
46
+
47
+ include RepresentedModel
48
+ end
49
+ ```
50
+
51
+ 3) Use the base representer, define your own CURIEs:
52
+ ```ruby
53
+ class Api::BaseRepresenter < HalApi::Representer
54
+ curies(:prx) do
55
+ [{
56
+ name: :foo,
57
+ href: "http://foo.bar/relation/{rel}",
58
+ templated: true
59
+ }]
60
+ end
61
+
62
+ def index_url_params
63
+ '{?page,per,zoom}'
64
+ end
65
+
66
+ def show_url_params
67
+ '{?zoom}'
68
+ end
69
+ end
70
+ ```
71
+
28
72
 
29
73
  ## Development
30
74
 
@@ -50,7 +50,7 @@ module HalApi::Controller::Actions
50
50
  def index_options
51
51
  valid_params_for_action(:index).tap do |options|
52
52
  options[:_keys] = options.keys
53
- options[:represent_with] = Api::PagedCollectionRepresenter
53
+ options[:represent_with] = HalApi::PagedCollection.representer
54
54
  end
55
55
  end
56
56
 
@@ -77,8 +77,8 @@ module HalApi::Controller::Actions
77
77
 
78
78
  def zoom_param
79
79
  @zoom_param ||= begin
80
- if (zp = params[:zoom]) && zp.present?
81
- zp.split(',').map(&:strip).compact.sort
80
+ if (zp = params[:zoom]) && !zp.nil?
81
+ Array(zp.split(',')).map(&:strip).compact.sort
82
82
  end
83
83
  end
84
84
  end
@@ -10,13 +10,12 @@ module HalApi::Controller::Exceptions
10
10
  wrapper = ::ActionDispatch::ExceptionWrapper.new(env, exception)
11
11
  log_error(env, wrapper)
12
12
 
13
- error = if exception.is_a?(HalApi::Errors::ApiError)
14
- exception
15
- else
16
- e = HalApi::Errors::ApiError.new(exception.message)
17
- e.set_backtrace(exception.backtrace)
18
- e
19
- end
13
+ error = exception
14
+ if !error.is_a?(HalApi::Errors::ApiError)
15
+ error = HalApi::Errors::ApiError.new(error.message).tap do |e|
16
+ e.set_backtrace(error.backtrace)
17
+ end
18
+ end
20
19
 
21
20
  respond_with(
22
21
  error,
@@ -82,15 +82,12 @@ module HalApi::Controller::Resources
82
82
  # Decorations
83
83
 
84
84
  def decorate_query(res)
85
- filtered(paged(sorted(scoped(res))))
85
+ filtered(paged(sorted(scoped(included(res)))))
86
86
  end
87
87
 
88
88
  def filtered(arel)
89
89
  keys = self.class.resources_params || []
90
90
  where_hash = params.slice(*keys)
91
- if where_hash.key?('story_id')
92
- where_hash['piece_id'] = where_hash.delete('story_id')
93
- end
94
91
  where_hash = where_hash.permit(where_hash.keys)
95
92
  arel = arel.where(where_hash) unless where_hash.blank?
96
93
  arel
@@ -13,6 +13,12 @@ class HalApi::PagedCollection
13
13
 
14
14
  def_delegators :request, :params
15
15
 
16
+ class_attribute :representer_class
17
+
18
+ def self.representer
19
+ representer_class || HalApi::PagedCollectionRepresenter
20
+ end
21
+
16
22
  def to_model
17
23
  self
18
24
  end
@@ -0,0 +1,63 @@
1
+ require 'hal_api/representer'
2
+
3
+ class HalApi::PagedCollectionRepresenter < HalApi::Representer
4
+ property :count
5
+ property :total
6
+
7
+ embeds :items, decorator: lambda{|*| item_decorator }, class: lambda{|*| item_class }, zoom: :always
8
+
9
+ link :prev do
10
+ href_url_helper(params.merge(page: represented.prev_page)) unless represented.first_page?
11
+ end
12
+
13
+ link :next do
14
+ href_url_helper(params.merge(page: represented.next_page)) unless represented.last_page?
15
+ end
16
+
17
+ link :first do
18
+ href_url_helper(params.merge(page: nil)) if represented.total_pages > 1
19
+ end
20
+
21
+ link :last do
22
+ href_url_helper(params.merge(page: represented.total_pages)) if represented.total_pages > 1
23
+ end
24
+
25
+ def params
26
+ represented.params
27
+ end
28
+
29
+ def self_url(represented)
30
+ href_url_helper(represented.params)
31
+ end
32
+
33
+ def profile_url(represented)
34
+ model_uri(:collection, represented.item_class)
35
+ end
36
+
37
+ # refactor to use single property, :url, that can be a method name, a string, or a lambda
38
+ # if it is a method name, execute against self - the representer - which has local url helpers methods
39
+ # if it is a sym/string, but self does not respond to it, then just use that string
40
+ # if it is a lambda, execute in the context against the represented.parent (if there is one) or represented
41
+ def href_url_helper(options={})
42
+ if represented_url.nil?
43
+ result = url_for(options.merge(only_path: true)) rescue nil
44
+ if represented.parent
45
+ result ||= polymorphic_path([:api, represented.parent, represented.item_class], options) rescue nil
46
+ end
47
+ result ||= polymorphic_path([:api, represented.item_class], options) rescue nil
48
+ return result
49
+ end
50
+
51
+ if represented_url.respond_to?(:call)
52
+ self.instance_exec(options, &represented_url)
53
+ elsif self.respond_to?(represented_url)
54
+ self.send(represented_url, options)
55
+ else
56
+ represented_url.to_s
57
+ end
58
+ end
59
+
60
+ def represented_url
61
+ @represented_url ||= represented.try(:url)
62
+ end
63
+ end
@@ -1,5 +1,5 @@
1
1
  module HalApi
2
2
  module Rails
3
- VERSION = "0.2.9"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -15,6 +15,10 @@ module HalApi::RepresentedModel
15
15
  is_root_resource
16
16
  end
17
17
 
18
+ def id_from_url(url)
19
+ Rails.application.routes.recognize_path(url)[:id]
20
+ end
21
+
18
22
  included do
19
23
  extend ActiveModel::Naming unless (method(:model_name) rescue nil)
20
24
  end
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  require 'active_support/concern'
3
2
  require 'hal_api/paged_collection'
4
3
 
@@ -10,15 +9,24 @@ module HalApi::Representer::Embeds
10
9
  Representable::Mapper.send(:include, Resources) if !Representable::Mapper.include?(Resources)
11
10
  end
12
11
 
12
+ def normalize_options!(options)
13
+ propagated_options, private_options = super(options)
14
+
15
+ # we want this to propogate, and be available for `skip_property?`, so don't delete
16
+ private_options[:zoom] = options[:zoom] if options.key?(:zoom)
17
+
18
+ [propagated_options, private_options]
19
+ end
20
+
13
21
  module Resources
14
22
 
15
- def skip_property?(binding, options)
16
- super(binding, options) || suppress_embed?(binding, options)
23
+ def skip_property?(binding, private_options)
24
+ super(binding, private_options) || suppress_embed?(binding, private_options)
17
25
  end
18
26
 
19
27
  # embed if zoomed
20
28
  def suppress_embed?(binding, options)
21
- name = (binding[:as] || binding.name).to_s
29
+ name = binding[:as].evaluate(self).to_s || binding.name
22
30
  embedded = !!binding[:embedded]
23
31
 
24
32
  # not embedded, return false - nothing to suppress
@@ -28,7 +36,7 @@ module HalApi::Representer::Embeds
28
36
  !embed_zoomed?(name, binding[:zoom], options[:zoom])
29
37
  end
30
38
 
31
- def embed_zoomed?(name, zoom_def=nil, zoom_param=nil)
39
+ def embed_zoomed?(name, zoom_def = nil, zoom_param = nil)
32
40
  # if the embed in the representer definition has `zoom: :always` defined
33
41
  # always embed it, even if it is in another embed
34
42
  # (this is really meant for collections where embedded items must be included)
@@ -70,7 +78,7 @@ module HalApi::Representer::Embeds
70
78
  per = getter_per == :all ? send(name).count : getter_per
71
79
  HalApi::PagedCollection.new(send(name).page(1).per(per), nil, opts.merge(parent: self))
72
80
  end
73
- options[:decorator] = Api::PagedCollectionRepresenter
81
+ options[:decorator] = HalApi::PagedCollection.representer
74
82
  end
75
83
 
76
84
  property(name, options)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hal_api-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Rhoden
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-10-11 00:00:00.000000000 Z
12
+ date: 2017-10-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -219,6 +219,7 @@ files:
219
219
  - lib/hal_api/controller/resources.rb
220
220
  - lib/hal_api/errors.rb
221
221
  - lib/hal_api/paged_collection.rb
222
+ - lib/hal_api/paged_collection_representer.rb
222
223
  - lib/hal_api/rails.rb
223
224
  - lib/hal_api/rails/version.rb
224
225
  - lib/hal_api/represented_model.rb
@@ -250,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
251
  version: '0'
251
252
  requirements: []
252
253
  rubyforge_project:
253
- rubygems_version: 2.6.4
254
+ rubygems_version: 2.4.5.2
254
255
  signing_key:
255
256
  specification_version: 4
256
257
  summary: JSON HAL APIs on Rails in the style of PRX