restpack_serializer 0.4.27 → 0.4.28

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d11e2c868b50066fc5b49f6b8d29e168faf2b796
4
- data.tar.gz: 00041f1def3a304b8ba4abbcebda28cd509b0f78
3
+ metadata.gz: 349f4fd2ffe9d0c1d9a7ccf4bcf724dd6ef59580
4
+ data.tar.gz: 9884153b0699c9f7fe9ced987b8284561cff48d3
5
5
  SHA512:
6
- metadata.gz: 1594047af58178562a684999fb18b5cb5089f334e741fa78572e6847e93248125fcad82a90f373dfba596264bc0f1023ec7c8dd9d27f91477fa0c454e200b5f3
7
- data.tar.gz: cf12374078885eb07db598c0a1d20c9c767a5e229becde7e9fab503e8851def1a4d2fd43378514b3166c5e50b620ab5c389857c80ae8b19b912125dfde103346
6
+ metadata.gz: b4792303f29da79c3dcf8518df080260d63dcdd89d620ca37b77388f2efdf0b2985d6e0d063624dc0d711c6aeadd6e12497ba0dc42266c2222bd5330bf1b88db
7
+ data.tar.gz: fb129097386e039f39fc6aa4964e97cdd36cf0a2825d53b27181c8d58486f5b9fef78856b76f083a0f9acae98aad29b4add0d5cb97b0c959179f4b900ef91b52
data/README.md CHANGED
@@ -12,6 +12,17 @@ restpack_serializer allows you to quickly provide a set of RESTful endpoints for
12
12
  * [An overview of RestPack](http://www.slideshare.net/gavinjoyce/taming-monolithic-monsters)
13
13
  * [JSON API](http://jsonapi.org/)
14
14
 
15
+ ## Getting Started
16
+
17
+ ### For rails projects:
18
+ After adding the gem `restpack_serializer` to your Gemfile, add this code to `config/initializers/restpack_serializer.rb`:
19
+
20
+ ```ruby
21
+ Dir[Rails.root.join('app/serializers/**/*.rb')].each do |path|
22
+ require path
23
+ end
24
+ ```
25
+
15
26
  ## Serialization
16
27
 
17
28
  Let's say we have an `Album` model:
@@ -1,5 +1,4 @@
1
1
  require 'kaminari'
2
- require 'protected_attributes'
3
2
 
4
3
  require 'restpack_serializer/version'
5
4
  require 'restpack_serializer/configuration'
@@ -7,9 +7,9 @@ module RestPack::Serializer
7
7
  def initialize(serializer, params = {}, scope = nil, context = {})
8
8
  params.symbolize_keys! if params.respond_to?(:symbolize_keys!)
9
9
 
10
- @page = 1
11
- @page_size = RestPack::Serializer.config.page_size
12
- @include = []
10
+ @page = params[:page] ? params[:page].to_i : 1
11
+ @page_size = params[:page_size] ? params[:page_size].to_i : RestPack::Serializer.config.page_size
12
+ @include = params[:include] ? params[:include].split(',').map(&:to_sym) : []
13
13
  @filters = filters_from_params(params, serializer)
14
14
  @sorting = sorting_from_params(params, serializer)
15
15
  @serializer = serializer
@@ -17,19 +17,13 @@ module RestPack::Serializer
17
17
  @scope = scope || model_class.send(:all)
18
18
  @context = context
19
19
  @include_links = true
20
-
21
- @page = params[:page].to_i if params[:page]
22
- @page_size = params[:page_size].to_i if params[:page_size]
23
- @include = params[:include].split(',').map(&:to_sym) if params[:include]
24
20
  end
25
21
 
26
22
  def scope_with_filters
27
23
  scope_filter = {}
24
+
28
25
  @filters.keys.each do |filter|
29
- value = @filters[filter]
30
- if value.is_a?(String)
31
- value = value.split(',')
32
- end
26
+ value = query_to_array(@filters[filter])
33
27
  scope_filter[filter] = value
34
28
  end
35
29
 
@@ -41,7 +35,7 @@ module RestPack::Serializer
41
35
  end
42
36
 
43
37
  def filters_as_url_params
44
- @filters.sort.map {|k,v| "#{k}=#{v.join(',')}" }.join('&')
38
+ @filters.sort.map { |k,v| map_filter_ids(k,v) }.join('&')
45
39
  end
46
40
 
47
41
  def sorting_as_url_params
@@ -73,5 +67,25 @@ module RestPack::Serializer
73
67
  end
74
68
  sorting_parameters
75
69
  end
70
+
71
+ def map_filter_ids(key,value)
72
+ case value
73
+ when Hash
74
+ value.map { |k,v| map_filter_ids(k,v) }
75
+ else
76
+ "#{key}=#{value.join(',')}"
77
+ end
78
+ end
79
+
80
+ def query_to_array(value)
81
+ case value
82
+ when String
83
+ value.split(',')
84
+ when Hash
85
+ value.each { |k, v| value[k] = query_to_array(v) }
86
+ else
87
+ value
88
+ end
89
+ end
76
90
  end
77
91
  end
@@ -71,6 +71,11 @@ module RestPack
71
71
  if foreign_key_value
72
72
  data[:links][association.name.to_sym] = foreign_key_value.to_s
73
73
  end
74
+ elsif association.macro == :has_many && association.options[:through]
75
+ ids = model.send(association.name).pluck(:id).map { |id| id.to_s }
76
+
77
+ data[:links] ||= {}
78
+ data[:links][association.name.to_sym] = ids
74
79
  end
75
80
  end
76
81
  data
@@ -85,10 +85,21 @@ module RestPack::Serializer::SideLoading
85
85
 
86
86
  def side_load_has_many(association, models, serializer)
87
87
  return {} if models.empty?
88
+
89
+ join_table = association.options[:through]
90
+
91
+ filters = if join_table
92
+ { join_table => { association.through_reflection.foreign_key.to_sym => models.map(&:id) } }
93
+ else
94
+ { association.foreign_key.to_sym => models.map(&:id) }
95
+ end
96
+
88
97
  options = RestPack::Serializer::Options.new(serializer.class)
89
- options.filters = { association.foreign_key.to_sym => models.map(&:id) }
98
+ options.scope = options.scope.joins(join_table) if join_table
99
+ options.filters = filters
90
100
  options.include_links = false
91
- return serializer.class.page_with_options(options)
101
+
102
+ serializer.class.page_with_options(options)
92
103
  end
93
104
 
94
105
  def association_from_include(include)
@@ -1,5 +1,5 @@
1
1
  module RestPack
2
2
  module Serializer
3
- VERSION = '0.4.27'
3
+ VERSION = '0.4.28'
4
4
  end
5
5
  end
@@ -19,7 +19,6 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_dependency 'activesupport', ['>= 4.0.3', '< 5.0']
21
21
  gem.add_dependency 'activerecord', ['>= 4.0.3', '< 5.0']
22
- gem.add_dependency 'protected_attributes', '~> 1.0.5'
23
22
  gem.add_dependency 'kaminari', '~> 0.15.1'
24
23
 
25
24
  gem.add_development_dependency 'restpack_gem', '~> 0.0.9'
@@ -31,4 +30,5 @@ Gem::Specification.new do |gem|
31
30
  gem.add_development_dependency 'database_cleaner', '~> 1.0.1'
32
31
  gem.add_development_dependency 'rspec'
33
32
  gem.add_development_dependency 'bump'
33
+ gem.add_development_dependency 'protected_attributes', '~> 1.0.5'
34
34
  end
data/spec/fixtures/db.rb CHANGED
@@ -41,6 +41,13 @@ ActiveRecord::Schema.define(:version => 1) do
41
41
  create_table "payments", :force => true do |t|
42
42
  t.integer "amount"
43
43
  t.integer "artist_id"
44
+ t.integer "fan_id"
45
+ t.datetime "created_at"
46
+ t.datetime "updated_at"
47
+ end
48
+
49
+ create_table "fans", :force => true do |t|
50
+ t.string "name"
44
51
  t.datetime "created_at"
45
52
  t.datetime "updated_at"
46
53
  end
@@ -53,6 +60,7 @@ module MyApp
53
60
  has_many :albums
54
61
  has_many :songs
55
62
  has_many :payments
63
+ has_many :fans, :through => :payments
56
64
  end
57
65
 
58
66
  class Album < ActiveRecord::Base
@@ -82,5 +90,12 @@ module MyApp
82
90
  attr_accessible :amount, :artist
83
91
 
84
92
  belongs_to :artist
93
+ belongs_to :fan
94
+ end
95
+
96
+ class Fan < ActiveRecord::Base
97
+ attr_accessible :name
98
+ has_many :payments
99
+ has_many :artists, :through => :albums
85
100
  end
86
101
  end
@@ -27,6 +27,11 @@ module MyApp
27
27
  class ArtistSerializer
28
28
  include RestPack::Serializer
29
29
  attributes :id, :name, :website
30
- can_include :albums, :songs
30
+ can_include :albums, :songs, :fans
31
+ end
32
+
33
+ class FanSerializer
34
+ include RestPack::Serializer
35
+ attributes :id, :name
31
36
  end
32
37
  end
@@ -139,14 +139,30 @@ describe RestPack::Serializer do
139
139
  end
140
140
 
141
141
  context "links" do
142
- let(:serializer) { MyApp::SongSerializer.new }
143
- it "includes 'links' data" do
144
- @album1 = FactoryGirl.create(:album_with_songs, song_count: 11)
145
- json = serializer.as_json(@album1.songs.first)
146
- json[:links].should == {
147
- artist: @album1.artist_id.to_s,
148
- album: @album1.id.to_s
149
- }
142
+ context "'belongs to' associations" do
143
+ let(:serializer) { MyApp::SongSerializer.new }
144
+
145
+ it "includes 'links' data for :belongs_to associations" do
146
+ @album1 = FactoryGirl.create(:album_with_songs, song_count: 11)
147
+ json = serializer.as_json(@album1.songs.first)
148
+ json[:links].should == {
149
+ artist: @album1.artist_id.to_s,
150
+ album: @album1.id.to_s
151
+ }
152
+ end
153
+ end
154
+
155
+ context "'has_many, through' associations" do
156
+ let(:artist_serializer) { MyApp::ArtistSerializer.new }
157
+
158
+ it "includes 'links' data when there are associated records" do
159
+ artist_with_fans = FactoryGirl.create :artist_with_fans
160
+
161
+ json = artist_serializer.as_json(artist_with_fans)
162
+ json[:links].should == {
163
+ fans: artist_with_fans.fans.collect {|obj| obj.id.to_s }
164
+ }
165
+ end
150
166
  end
151
167
  end
152
168
  end
@@ -2,13 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  describe RestPack::Serializer::SideLoading do
4
4
  context "when side-loading" do
5
+ let(:side_loads) { MyApp::ArtistSerializer.side_loads(models, options) }
6
+
5
7
  describe ".has_many" do
6
8
 
7
9
  before(:each) do
8
10
  @artist1 = FactoryGirl.create(:artist_with_albums, album_count: 2)
9
11
  @artist2 = FactoryGirl.create(:artist_with_albums, album_count: 1)
10
12
  end
11
- let(:side_loads) { MyApp::ArtistSerializer.side_loads(models, options) }
12
13
 
13
14
  context "with a single model" do
14
15
  let(:models) { [@artist1] }
@@ -37,7 +38,35 @@ describe RestPack::Serializer::SideLoading do
37
38
  end
38
39
  end
39
40
  end
41
+ end
42
+
43
+ describe '.has_many through' do
44
+ context 'when including :fans' do
45
+ let(:options) { RestPack::Serializer::Options.new(MyApp::ArtistSerializer, { "include" => "fans" }) }
46
+ let(:artist_1) {FactoryGirl.create :artist_with_fans}
47
+ let(:artist_2) {FactoryGirl.create :artist_with_fans}
40
48
 
49
+ context "with a single model" do
50
+ let(:models) {[artist_1]}
51
+
52
+ it 'returns side-loaded fans' do
53
+ side_loads[:fans].count.should == artist_1.fans.count
54
+ side_loads[:meta][:fans][:page].should == 1
55
+ side_loads[:meta][:fans][:count].should == artist_1.fans.count
56
+ end
57
+ end
58
+ context "with a multiple models" do
59
+ let(:models) {[artist_1, artist_2]}
60
+
61
+ it 'returns side-loaded fans' do
62
+ expected_count = artist_1.fans.count + artist_2.fans.count
63
+
64
+ side_loads[:fans].count.should == expected_count
65
+ side_loads[:meta][:fans][:page].should == 1
66
+ side_loads[:meta][:fans][:count].should == expected_count
67
+ end
68
+ end
69
+ end
41
70
  end
42
71
  end
43
72
  end
@@ -14,6 +14,15 @@ FactoryGirl.define do
14
14
  create_list(:album_with_songs, evaluator.album_count, artist: artist)
15
15
  end
16
16
  end
17
+
18
+ factory :artist_with_fans do
19
+ ignore do
20
+ fans_count 3
21
+ end
22
+ after(:create) do |artist, evaluator|
23
+ create_list(:payment, evaluator.fans_count, artist: artist)
24
+ end
25
+ end
17
26
  end
18
27
 
19
28
  factory :album, :class => MyApp::Album do
@@ -41,5 +50,10 @@ FactoryGirl.define do
41
50
  factory :payment, :class => MyApp::Payment do
42
51
  amount 999
43
52
  artist
53
+ fan
54
+ end
55
+
56
+ factory :fan, :class => MyApp::Fan do
57
+ sequence(:name) {|n| "Fan ##{n}"}
44
58
  end
45
59
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restpack_serializer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.27
4
+ version: 0.4.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gavin Joyce
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-12 00:00:00.000000000 Z
11
+ date: 2014-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -50,20 +50,6 @@ dependencies:
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '5.0'
53
- - !ruby/object:Gem::Dependency
54
- name: protected_attributes
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - "~>"
58
- - !ruby/object:Gem::Version
59
- version: 1.0.5
60
- type: :runtime
61
- prerelease: false
62
- version_requirements: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - "~>"
65
- - !ruby/object:Gem::Version
66
- version: 1.0.5
67
53
  - !ruby/object:Gem::Dependency
68
54
  name: kaminari
69
55
  requirement: !ruby/object:Gem::Requirement
@@ -204,6 +190,20 @@ dependencies:
204
190
  - - ">="
205
191
  - !ruby/object:Gem::Version
206
192
  version: '0'
193
+ - !ruby/object:Gem::Dependency
194
+ name: protected_attributes
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: 1.0.5
200
+ type: :development
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - "~>"
205
+ - !ruby/object:Gem::Version
206
+ version: 1.0.5
207
207
  description: Model serialization, paging, side-loading and filtering
208
208
  email:
209
209
  - gavinjoyce@gmail.com