From c69a14186bda8d5789bab43ad297ec78e3acf2c8 Mon Sep 17 00:00:00 2001 From: Michael Parrish Date: Fri, 6 Feb 2015 16:31:22 -0600 Subject: [PATCH 1/2] Allow non-model names for associations --- lib/restpack_serializer/options.rb | 4 ++-- lib/restpack_serializer/serializable/paging.rb | 9 ++++++--- .../serializable/side_load_data_builder.rb | 5 +++-- lib/restpack_serializer/serializable/side_loading.rb | 7 +++---- spec/fixtures/db.rb | 1 + spec/fixtures/serializers.rb | 2 +- spec/serializable/side_loading/has_many_spec.rb | 11 +++++++++++ 7 files changed, 27 insertions(+), 12 deletions(-) diff --git a/lib/restpack_serializer/options.rb b/lib/restpack_serializer/options.rb index 83728b8..c125169 100644 --- a/lib/restpack_serializer/options.rb +++ b/lib/restpack_serializer/options.rb @@ -2,9 +2,9 @@ module RestPack::Serializer class Options attr_accessor :page, :page_size, :include, :filters, :serializer, :model_class, :scope, :context, :include_links, - :sorting + :sorting, :key - def initialize(serializer, params = {}, scope = nil, context = {}) + def initialize(serializer, params = {}, scope = nil, context = {}, key = nil) params.symbolize_keys! if params.respond_to?(:symbolize_keys!) @page = params[:page] ? params[:page].to_i : 1 diff --git a/lib/restpack_serializer/serializable/paging.rb b/lib/restpack_serializer/serializable/paging.rb index 9ad2f46..266d687 100644 --- a/lib/restpack_serializer/serializable/paging.rb +++ b/lib/restpack_serializer/serializable/paging.rb @@ -11,12 +11,15 @@ def page_with_options(options) page = page.reorder(options.sorting) if options.sorting.any? result = RestPack::Serializer::Result.new - result.resources[self.key] = serialize_page(page, options) - result.meta[self.key] = serialize_meta(page, options) + result.resources[options.key || self.key] = serialize_page(page, options) + result.meta[options.key || self.key] = serialize_meta(page, options) if options.include_links result.links = self.links - Array(RestPack::Serializer::Factory.create(*options.include)).each do |serializer| + options.include.each do |inclusion| + association = model_class.reflect_on_association inclusion + class_name = association ? association.class_name : inclusion + serializer = RestPack::Serializer::Factory.create class_name result.links.merge! serializer.class.links end end diff --git a/lib/restpack_serializer/serializable/side_load_data_builder.rb b/lib/restpack_serializer/serializable/side_load_data_builder.rb index 495cfad..d21eb80 100644 --- a/lib/restpack_serializer/serializable/side_load_data_builder.rb +++ b/lib/restpack_serializer/serializable/side_load_data_builder.rb @@ -12,11 +12,12 @@ def side_load_belongs_to foreign_keys = @models.map { |model| model.send(@association.foreign_key) }.uniq.compact side_load = foreign_keys.any? ? @association.klass.find(foreign_keys) : [] json_model_data = side_load.map { |model| @serializer.as_json(model) } - { @association.plural_name.to_sym => json_model_data, meta: { } } + { @association.class_name.underscore.pluralize.to_sym => json_model_data, meta: { } } end def side_load_has_many has_association_relation do |options| + options.key = @association.name if join_table = @association.options[:through] options.scope = options.scope.joins(join_table).distinct association_fk = @association.through_reflection.foreign_key.to_sym @@ -30,7 +31,7 @@ def side_load_has_many def side_load_has_and_belongs_to_many has_association_relation do |options| join_table_name = @association.join_table - join_clause = "join #{join_table_name} on #{@association.plural_name}.id = #{join_table_name}.#{@association.class_name.foreign_key}" + join_clause = "join #{join_table_name} on #{@association.klass.table_name }.id = #{join_table_name}.#{@association.class_name.foreign_key}" options.scope = options.scope.joins(join_clause) association_fk = @association.foreign_key.to_sym options.filters = { join_table_name.to_sym => { association_fk => model_ids } } diff --git a/lib/restpack_serializer/serializable/side_loading.rb b/lib/restpack_serializer/serializable/side_loading.rb index e5a1b12..dd36b6d 100644 --- a/lib/restpack_serializer/serializable/side_loading.rb +++ b/lib/restpack_serializer/serializable/side_loading.rb @@ -28,16 +28,15 @@ def links associations.each do |association| if association.macro == :belongs_to link_key = "#{self.key}.#{association.name}" - href = "/#{association.plural_name}/{#{link_key}}" + href = "/#{association.class_name.underscore.pluralize}/{#{link_key}}" elsif association.macro.to_s.match(/has_/) - singular_key = self.key.to_s.singularize link_key = "#{self.key}.#{association.plural_name}" - href = "/#{association.plural_name}?#{singular_key}_id={#{key}.id}" + href = "/#{association.class_name.underscore.pluralize}?#{association.foreign_key}={#{key}.id}" end links.merge!(link_key => { :href => href_prefix + href, - :type => association.plural_name.to_sym + :type => association.class_name.underscore.pluralize.to_sym } ) end diff --git a/spec/fixtures/db.rb b/spec/fixtures/db.rb index be89b82..ceaa562 100644 --- a/spec/fixtures/db.rb +++ b/spec/fixtures/db.rb @@ -69,6 +69,7 @@ class Artist < ActiveRecord::Base attr_accessible :name, :website has_many :albums + has_many :records, class_name: 'Album' has_many :songs has_many :payments has_many :fans, :through => :payments diff --git a/spec/fixtures/serializers.rb b/spec/fixtures/serializers.rb index ff7e88a..cb3a547 100644 --- a/spec/fixtures/serializers.rb +++ b/spec/fixtures/serializers.rb @@ -27,7 +27,7 @@ class AlbumReviewSerializer class ArtistSerializer include RestPack::Serializer attributes :id, :name, :website - can_include :albums, :songs, :fans, :stalkers + can_include :albums, :records, :songs, :fans, :stalkers end class FanSerializer diff --git a/spec/serializable/side_loading/has_many_spec.rb b/spec/serializable/side_loading/has_many_spec.rb index 77aef99..5a54e72 100644 --- a/spec/serializable/side_loading/has_many_spec.rb +++ b/spec/serializable/side_loading/has_many_spec.rb @@ -38,6 +38,17 @@ end end end + + context 'with a model renaming an association' do + let(:models){ [@artist1] } + let(:options) { RestPack::Serializer::Options.new(MyApp::ArtistSerializer, { "include" => "records" }) } + + it 'should return side-loaded records' do + side_loads[:records].count.should == @artist1.albums.count + side_loads[:meta][:records][:page].should == 1 + side_loads[:meta][:records][:count].should == @artist1.albums.count + end + end end describe '.has_many through' do From c8fdb1ec6b9497c09e800ddf034d9ff13669c33b Mon Sep 17 00:00:00 2001 From: Michael Parrish Date: Fri, 6 Feb 2015 16:41:10 -0600 Subject: [PATCH 2/2] Fix renamed belongs_to associations --- .../serializable/side_load_data_builder.rb | 2 +- spec/fixtures/db.rb | 1 + spec/fixtures/serializers.rb | 2 +- spec/serializable/paging_spec.rb | 2 ++ spec/serializable/serializer_spec.rb | 1 + spec/serializable/side_loading/belongs_to_spec.rb | 12 ++++++++++++ 6 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/restpack_serializer/serializable/side_load_data_builder.rb b/lib/restpack_serializer/serializable/side_load_data_builder.rb index d21eb80..9d4e9f8 100644 --- a/lib/restpack_serializer/serializable/side_load_data_builder.rb +++ b/lib/restpack_serializer/serializable/side_load_data_builder.rb @@ -12,7 +12,7 @@ def side_load_belongs_to foreign_keys = @models.map { |model| model.send(@association.foreign_key) }.uniq.compact side_load = foreign_keys.any? ? @association.klass.find(foreign_keys) : [] json_model_data = side_load.map { |model| @serializer.as_json(model) } - { @association.class_name.underscore.pluralize.to_sym => json_model_data, meta: { } } + { @association.plural_name.to_sym => json_model_data, meta: { } } end def side_load_has_many diff --git a/spec/fixtures/db.rb b/spec/fixtures/db.rb index ceaa562..2382e57 100644 --- a/spec/fixtures/db.rb +++ b/spec/fixtures/db.rb @@ -96,6 +96,7 @@ class Song < ActiveRecord::Base attr_accessible :title, :artist, :album belongs_to :artist + belongs_to :record, class_name: 'Album', foreign_key: 'album_id' belongs_to :album end diff --git a/spec/fixtures/serializers.rb b/spec/fixtures/serializers.rb index cb3a547..72214ee 100644 --- a/spec/fixtures/serializers.rb +++ b/spec/fixtures/serializers.rb @@ -2,7 +2,7 @@ module MyApp class SongSerializer include RestPack::Serializer attributes :id, :title, :album_id - can_include :albums, :artists + can_include :albums, :records, :artists can_filter_by :title can_sort_by :id, :title diff --git a/spec/serializable/paging_spec.rb b/spec/serializable/paging_spec.rb index 2eba6a2..8a3b38c 100644 --- a/spec/serializable/paging_spec.rb +++ b/spec/serializable/paging_spec.rb @@ -32,6 +32,7 @@ it "includes links" do page[:links].should == { 'songs.album' => { :href => "/albums/{songs.album}", :type => :albums }, + 'songs.record' => { :href => "/albums/{songs.record}", :type => :albums }, 'songs.artist' => { :href => "/artists/{songs.artist}", :type => :artists } } end @@ -99,6 +100,7 @@ album_id: first.album_id, links: { album: first.album_id.to_s, + record: first.album_id.to_s, artist: first.artist_id.to_s } } diff --git a/spec/serializable/serializer_spec.rb b/spec/serializable/serializer_spec.rb index aaa3e3a..754d49f 100644 --- a/spec/serializable/serializer_spec.rb +++ b/spec/serializable/serializer_spec.rb @@ -147,6 +147,7 @@ def custom_attributes json = serializer.as_json(@album1.songs.first) json[:links].should == { artist: @album1.artist_id.to_s, + record: @album1.id.to_s, album: @album1.id.to_s } end diff --git a/spec/serializable/side_loading/belongs_to_spec.rb b/spec/serializable/side_loading/belongs_to_spec.rb index 95b1266..d69878d 100644 --- a/spec/serializable/side_loading/belongs_to_spec.rb +++ b/spec/serializable/side_loading/belongs_to_spec.rb @@ -67,6 +67,18 @@ end end + context 'with a renamed association' do + let(:models) { [MyApp::Song.first] } + let(:options) { RestPack::Serializer::Options.new(MyApp::SongSerializer, { "include" => "records" }) } + + it 'should side-load records' do + side_loads.should == { + records: [MyApp::AlbumSerializer.as_json(MyApp::Song.first.album)], + meta: { } + } + end + end + context 'without an associated model' do let!(:b_side) { FactoryGirl.create(:song, album: nil) } let(:models) { [b_side] }