Skip to content

Commit

Permalink
Extract and generalize embedded attributes in serializers
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Parrish committed Jul 30, 2015
1 parent 0123e12 commit ec11e12
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 53 deletions.
7 changes: 7 additions & 0 deletions app/serializers/board_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
class BoardSerializer
include TalkSerializer
include EmbeddedAttributes

all_attributes
can_include :discussions, :parent, :sub_boards
can_filter_by :subject_default
can_sort_by :created_at
self.default_sort = 'created_at'
self.eager_loads = [:project]

def custom_attributes
super.merge attributes_from :project
end
end
24 changes: 1 addition & 23 deletions app/serializers/comment_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class CommentSerializer
include TalkSerializer
include EmbeddedAttributes
include ModerationActions

all_attributes
Expand All @@ -17,29 +18,6 @@ def custom_attributes
.merge focus: focus, user_display_name: model.user.display_name
end

def discussion_attributes
%w(comments_count subject_default title updated_at users_count)
end

def board_attributes
%w(comments_count description discussions_count id parent_id subject_default title users_count)
end

def project_attributes
%w(slug)
end

def attributes_from(relation)
{ }.tap do |attrs|
record_attributes = model.send(relation).attributes rescue { }
send("#{ relation }_attributes").each do |attr|
value = record_attributes[attr]
value = value.to_s if attr =~ /(_id)|(^id$)$/
attrs[:"#{ relation }_#{ attr }"] = value
end
end
end

def focus
focus_serializer.as_json model.focus
rescue
Expand Down
26 changes: 26 additions & 0 deletions app/serializers/concerns/embedded_attributes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module EmbeddedAttributes
extend ActiveSupport::Concern

def discussion_attributes
%w(comments_count subject_default title updated_at users_count)
end

def board_attributes
%w(comments_count description discussions_count id parent_id subject_default title users_count)
end

def project_attributes
%w(slug)
end

def attributes_from(relation)
{ }.tap do |attrs|
record_attributes = model.send(relation).attributes rescue { }
send("#{ relation }_attributes").each do |attr|
value = record_attributes[attr]
value = value.to_s if attr =~ /(_id)|(^id$)$/
attrs[:"#{ relation }_#{ attr }"] = value
end
end
end
end
8 changes: 6 additions & 2 deletions app/serializers/discussion_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
class DiscussionSerializer
include TalkSerializer
include EmbeddedAttributes
include ModerationActions

all_attributes
can_include :comments, :board, :user
can_filter_by :title, :subject_default, :sticky
can_sort_by :updated_at, :sticky, :sticky_position
self.default_sort = '-sticky,sticky_position,-updated_at'
self.eager_loads = [:user]
self.eager_loads = [:user, :board, :project]

def custom_attributes
super.merge user_display_name: model.user.display_name
super
.merge(attributes_from(:project))
.merge(attributes_from(:board))
.merge user_display_name: model.user.display_name
end
end
1 change: 1 addition & 0 deletions spec/serializers/board_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
it_behaves_like 'a talk serializer', exposing: :all, including: [:discussions, :parent, :sub_boards] do
let(:parent){ create :board }
let(:model_instance){ create :board_with_subboards, parent: parent }
it_behaves_like 'a serializer with embedded attributes', relations: [:project]
end
end
28 changes: 1 addition & 27 deletions spec/serializers/comment_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@
let(:focus){ create :subject }
let(:model_instance){ create :comment_for_focus, focus: focus }
let(:json){ CommentSerializer.resource(id: model_instance.id)[:comments].first }
let!(:project) do
Project.find_by_id(model_instance.project_id) ||
create(:project, id: model_instance.project_id)
end
subject{ json }
it_behaves_like 'a serializer with embedded attributes', relations: [:project, :discussion, :board]

its([:user_display_name]){ is_expected.to eql model_instance.user.display_name }
it{ is_expected.to include :focus }
Expand All @@ -27,29 +24,6 @@
it{ is_expected.to have_key :updated_at }
it{ is_expected.to have_key :project_id }
end

describe '#board_attributes' do
its([:board_comments_count]){ is_expected.to eql model_instance.board.comments_count }
its([:board_description]){ is_expected.to eql model_instance.board.description }
its([:board_discussions_count]){ is_expected.to eql model_instance.board.discussions_count }
its([:board_id]){ is_expected.to eql model_instance.board.id.to_s }
its([:board_parent_id]){ is_expected.to eql model_instance.board.parent_id.to_s }
its([:board_subject_default]){ is_expected.to eql model_instance.board.subject_default }
its([:board_title]){ is_expected.to eql model_instance.board.title }
its([:board_users_count]){ is_expected.to eql model_instance.board.users_count }
end

describe '#discussion_attributes' do
its([:discussion_comments_count]){ is_expected.to eql model_instance.discussion.comments_count }
its([:discussion_subject_default]){ is_expected.to eql model_instance.discussion.subject_default }
its([:discussion_title]){ is_expected.to eql model_instance.discussion.title }
its([:discussion_updated_at]){ is_expected.to be_within(1.second).of model_instance.discussion.updated_at }
its([:discussion_users_count]){ is_expected.to eql model_instance.discussion.users_count }
end

describe '#project_attributes' do
its([:project_slug]){ is_expected.to eql model_instance.project.slug }
end
end

it_behaves_like 'a moderatable serializer' do
Expand Down
5 changes: 4 additions & 1 deletion spec/serializers/discussion_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
RSpec.describe DiscussionSerializer, type: :serializer do
it_behaves_like 'a talk serializer', exposing: :all, including: [:comments, :board, :user] do
subject{ json }
it_behaves_like 'a serializer with embedded attributes', relations: [:project, :board]

its([:user_display_name]){ is_expected.to eql model_instance.user.display_name }

describe '.default_sort' do
let(:board){ create :board }
let!(:discussion1){ create :discussion, board: board, updated_at: 1.minute.ago.utc }
let!(:model_instance){ create :discussion, board: board, updated_at: 1.minute.ago.utc }
let(:discussion1){ model_instance }
let!(:discussion2){ create :discussion, board: board, updated_at: 2.minutes.ago.utc }
let!(:sticky1){ create :discussion, board: board, updated_at: 2.minute.ago.utc, sticky: true, sticky_position: 1 }
let!(:sticky2){ create :discussion, board: board, updated_at: 1.minutes.ago.utc, sticky: true, sticky_position: 2 }
Expand Down
40 changes: 40 additions & 0 deletions spec/support/shared_examples_for_embedded_attributes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'rspec'

RSpec.shared_examples_for 'a serializer with embedded attributes' do |relations: []|
let!(:project) do
Project.find_by_id(model_instance.project_id) ||
create(:project, id: model_instance.project_id)
end

if relations.include?(:board)
describe '#board_attributes' do
subject{ json }
its([:board_comments_count]){ is_expected.to eql model_instance.board.comments_count }
its([:board_description]){ is_expected.to eql model_instance.board.description }
its([:board_discussions_count]){ is_expected.to eql model_instance.board.discussions_count }
its([:board_id]){ is_expected.to eql model_instance.board.id.to_s }
its([:board_parent_id]){ is_expected.to eql model_instance.board.parent_id.to_s }
its([:board_subject_default]){ is_expected.to eql model_instance.board.subject_default }
its([:board_title]){ is_expected.to eql model_instance.board.title }
its([:board_users_count]){ is_expected.to eql model_instance.board.users_count }
end
end

if relations.include?(:discussion)
describe '#discussion_attributes' do
subject{ json }
its([:discussion_comments_count]){ is_expected.to eql model_instance.discussion.comments_count }
its([:discussion_subject_default]){ is_expected.to eql model_instance.discussion.subject_default }
its([:discussion_title]){ is_expected.to eql model_instance.discussion.title }
its([:discussion_updated_at]){ is_expected.to be_within(1.second).of model_instance.discussion.updated_at }
its([:discussion_users_count]){ is_expected.to eql model_instance.discussion.users_count }
end
end

if relations.include?(:project)
describe '#project_attributes' do
subject{ json }
its([:project_slug]){ is_expected.to eql model_instance.project.slug }
end
end
end

0 comments on commit ec11e12

Please sign in to comment.