Skip to content

Commit

Permalink
Towards model serializers
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Parrish committed Dec 5, 2014
1 parent 5e1b56b commit 33a3324
Show file tree
Hide file tree
Showing 27 changed files with 226 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ source 'https://rubygems.org'

gem 'rails', '~> 4.2.0.rc1'
gem 'pg'
gem 'jbuilder', '~> 2.2'
gem 'restpack_serializer', '~> 0.5.6'
gem 'sdoc', '~> 0.4', group: :doc
gem 'spring', group: :development

Expand Down
12 changes: 8 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ GEM
hike (1.2.3)
hitimes (1.2.2)
i18n (0.7.0.beta1)
jbuilder (2.2.5)
activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2)
json (1.8.1)
kaminari (0.16.1)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
listen (2.8.3)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
Expand Down Expand Up @@ -122,6 +122,10 @@ GEM
ffi (>= 0.5.0)
rdoc (4.1.2)
json (~> 1.4)
restpack_serializer (0.5.6)
activerecord (>= 4.0.3, < 5.0)
activesupport (>= 4.0.3, < 5.0)
kaminari (~> 0.16.1)
rspec (3.1.0)
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
Expand Down Expand Up @@ -172,11 +176,11 @@ PLATFORMS
DEPENDENCIES
factory_girl_rails
guard-rspec
jbuilder (~> 2.2)
pg
pry
rails (~> 4.2.0.rc1)
rb-fsevent
restpack_serializer (~> 0.5.6)
rspec-rails
sdoc (~> 0.4)
spring
Expand Down
5 changes: 5 additions & 0 deletions app/serializers/board_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class BoardSerializer
include TalkSerializer
all_attributes
can_include :discussions
end
11 changes: 11 additions & 0 deletions app/serializers/comment_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CommentSerializer
include TalkSerializer
all_attributes
can_include :focus

def links
{
focus_type: model.focus_type
} if model.focus_id
end
end
20 changes: 20 additions & 0 deletions app/serializers/concerns/talk_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module TalkSerializer
extend ActiveSupport::Concern

included do
include RestPack::Serializer
attr_reader :model
attributes :href, :links
can_filter_by(:section) if model_class.columns_hash.has_key? 'section'
end

module ClassMethods
def all_attributes
attributes *model_class.attribute_names
end
end

def links
{ }
end
end
5 changes: 5 additions & 0 deletions app/serializers/conversation_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class ConversationSerializer
include TalkSerializer
all_attributes
can_include :messages
end
5 changes: 5 additions & 0 deletions app/serializers/discussion_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class DiscussionSerializer
include TalkSerializer
all_attributes
can_include :comments, :board, :user
end
4 changes: 4 additions & 0 deletions app/serializers/focus_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class FocusSerializer
include TalkSerializer
all_attributes
end
14 changes: 14 additions & 0 deletions app/serializers/message_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class MessageSerializer
include TalkSerializer
all_attributes
attributes :sender, :recipient
can_include :conversation

def sender
UserSerializer.as_json model.sender
end

def recipient
UserSerializer.as_json model.recipient
end
end
4 changes: 4 additions & 0 deletions app/serializers/moderation_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class ModerationSerializer
include TalkSerializer
all_attributes
end
4 changes: 4 additions & 0 deletions app/serializers/tag_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class TagSerializer
include TalkSerializer
all_attributes
end
5 changes: 5 additions & 0 deletions app/serializers/user_conversation_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class UserConversationSerializer
include TalkSerializer
all_attributes
can_include :user, :conversation
end
4 changes: 4 additions & 0 deletions app/serializers/user_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class UserSerializer
include TalkSerializer
all_attributes
end
4 changes: 3 additions & 1 deletion config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
module Talk
class Application < Rails::Application
config.autoload_paths += [
'app/services'
'app/services',
'app/serializers/concerns',
'app/serializers'
].collect{ |path| Rails.root.join path }
end
end
19 changes: 19 additions & 0 deletions config/initializers/restpack_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'restpack_serializer'

module RestPack::Serializer
class SideLoadDataBuilder
# Bug fix. Prevent side loaded association from try to find non-existant records
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: { } }
end
end
end

# preload autoloaded serializers
Dir[Rails.root.join('app/serializers/**/*.rb')].sort.each do |path|
name = path.match(/serializers\/(.+)\.rb$/)[1]
name.classify.constantize unless path =~ /serializers\/concerns/
end
2 changes: 1 addition & 1 deletion spec/factories/tags.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :tag do

name{ "tag#{ id }" }
end

end
5 changes: 5 additions & 0 deletions spec/serializers/board_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe BoardSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all, including: [:discussions]
end
13 changes: 13 additions & 0 deletions spec/serializers/comment_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require 'spec_helper'

RSpec.describe CommentSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all, including: [:focus]

it 'should specify the focus type in links' do
subject = create :subject
comment = create :comment_for_focus, focus: subject
json = CommentSerializer.resource id: comment.id
comment_json = json[:comments].first
expect(comment_json[:links]).to eql focus: subject.id.to_s, focus_type: 'Subject'
end
end
5 changes: 5 additions & 0 deletions spec/serializers/conversation_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe ConversationSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all, including: [:messages]
end
5 changes: 5 additions & 0 deletions spec/serializers/discussion_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe DiscussionSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all, including: [:comments, :board, :user]
end
5 changes: 5 additions & 0 deletions spec/serializers/focus_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe FocusSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all
end
14 changes: 14 additions & 0 deletions spec/serializers/message_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'spec_helper'

RSpec.describe MessageSerializer, type: :serializer do
let(:conversation){ create :conversation_with_messages }
let(:object){ conversation.messages.first }
it_behaves_like 'a talk serializer', exposing: :all, including: [:conversation]

it 'should sideload sender' do
json = MessageSerializer.resource id: object.id
message_json = json[:messages].first
expect(message_json[:sender][:id]).to eql object.sender.id
expect(message_json[:recipient][:id]).to eql object.recipient.id
end
end
5 changes: 5 additions & 0 deletions spec/serializers/moderation_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe ModerationSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all
end
5 changes: 5 additions & 0 deletions spec/serializers/tag_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe TagSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all
end
5 changes: 5 additions & 0 deletions spec/serializers/user_conversation_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe UserConversationSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all, including: [:user, :conversation]
end
5 changes: 5 additions & 0 deletions spec/serializers/user_serializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'spec_helper'

RSpec.describe UserSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all
end
46 changes: 46 additions & 0 deletions spec/support/shared_examples_for_talk_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
RSpec.shared_context 'a serializer' do
let(:serializer){ described_class }
let(:model){ serializer.model_class }
let(:instance){ FactoryGirl.create serializer.singular_key }
let(:model_instance){ instance }
let(:json){ serializer.as_json model_instance }
end

RSpec.shared_examples 'a talk serializer' do |exposing: nil, including: nil|
include_context 'a serializer'
let(:model_instance){ defined?(object) ? object : instance }

describe 'attributes' do
subject{ json }

if exposing == :all
described_class.model_class.attribute_names.each do |name|
it{ is_expected.to include name.to_sym }
end
elsif exposing
exposing.each do |name|
it{ is_expected.to include name.to_sym }
end
end

it{ is_expected.to include :href }
end

describe 'associations' do
if including
including.each do |association|
it "should allow inclusion of #{ association }" do
association = association.to_s
json = serializer.resource id: model_instance.id, include: association
association_key = association.to_s.pluralize.to_sym
expect(json[:linked]).to include association_key

macro = model.reflect_on_association(association).macro
unless macro.in? [:belongs_to, :has_one]
expect(json[:meta]).to include association_key
end
end
end
end
end
end

0 comments on commit 33a3324

Please sign in to comment.