Skip to content

Commit

Permalink
Fix AR leakage (#30)
Browse files Browse the repository at this point in the history
* First version

* as_json instead of to_dto

* Improve tests

* Minor change

* Call .to_dto if available on methods' result

* Test PORO as result of method
  • Loading branch information
santib committed Jul 6, 2022
1 parent 90a32ed commit ea39c11
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 9 deletions.
21 changes: 17 additions & 4 deletions lib/ar2dto/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ def initialize(model, options)
end

def serializable_hash
hash = model.serializable_hash(options&.except(:include))

hash_with_associations(hash)
hash = model.serializable_hash(options&.except(:methods, :include))
hash = add_methods(hash)
add_associations(hash)
end

private
Expand All @@ -22,7 +22,20 @@ def apply_configs(options)
options
end

def hash_with_associations(hash)
def add_methods(hash)
options&.dig(:methods)&.each do |method|
result = model.send(method)
result = if result.respond_to?(:to_dto)
result.to_dto
else
result.as_json
end
hash[method.to_s] = result
end
hash
end

def add_associations(hash)
includes.each do |association, opts|
records = model.send(association)
hash[association.to_s] = records ? records_dto(records, opts) : nil
Expand Down
31 changes: 31 additions & 0 deletions spec/ar2dto/record_to_dto/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,37 @@
expect(subject.superman?).to eq(false)
end
end

context "when including methods that return an ActiveRecord object" do
let(:options) do
{ methods: %i[myself other] }
end

context "if it responds to #to_dto" do
it "gets converted into a DTO" do
expect(subject.myself).to be_a(UserDTO)
expect(subject.myself.first_name).to eq("Sandy")
end
end

context "if it doesn't respond to #to_dto" do
it "gets converted into a hash" do
expect(subject.other).to be_a(Hash)
expect(subject.other["text"]).to eq("Strange Sandy")
end
end
end

context "when including methods that return a PORO" do
let(:options) do
{ methods: %i[poro] }
end

it "gets converted into a hash" do
expect(subject.poro).to be_a(Hash)
expect(subject.poro["created_at"]).to eq(user.created_at.as_json)
end
end
end

context "when excluding attributes via except" do
Expand Down
37 changes: 37 additions & 0 deletions spec/ar2dto/relation_to_dto/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,43 @@
expect(subject.first.full_name).to eq("Sandy Doe")
expect(subject.second.full_name).to eq("Kent Simpson")
end

context "when including methods that return an ActiveRecord object" do
let(:options) do
{ methods: %i[myself other] }
end

context "if it responds to #to_dto" do
it "gets converted into a DTO" do
expect(subject.first.myself).to be_a(UserDTO)
expect(subject.first.myself.first_name).to eq("Sandy")
expect(subject.second.myself).to be_a(UserDTO)
expect(subject.second.myself.first_name).to eq("Kent")
end
end

context "if it doesn't respond to #to_dto" do
it "gets converted into a hash" do
expect(subject.first.other).to be_a(Hash)
expect(subject.first.other["text"]).to eq("Strange Sandy")
expect(subject.second.other).to be_a(Hash)
expect(subject.second.other["text"]).to eq("Strange Kent")
end
end
end

context "when including methods that return a PORO" do
let(:options) do
{ methods: %i[poro] }
end

it "gets converted into a hash" do
expect(subject.first.poro).to be_a(Hash)
expect(subject.first.poro["created_at"]).to eq(user.created_at.as_json)
expect(subject.second.poro).to be_a(Hash)
expect(subject.second.poro["created_at"]).to eq(another_user.created_at.as_json)
end
end
end

context "when excluding attributes via except" do
Expand Down
4 changes: 4 additions & 0 deletions spec/support/fixtures/other.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

class Other < ActiveRecord::Base
end
7 changes: 7 additions & 0 deletions spec/support/fixtures/simple_poro.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class SimplePoro
def initialize(created_at:)
@created_at = created_at
end
end
12 changes: 12 additions & 0 deletions spec/support/fixtures/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,16 @@ def strange_name
def superman?
full_name == "Clark Kent"
end

def myself
self
end

def other
Other.new(text: strange_name)
end

def poro
SimplePoro.new(created_at: created_at)
end
end
6 changes: 6 additions & 0 deletions spec/support/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@

t.timestamps
end

create_table :others, force: true do |t|
t.text :text

t.timestamps
end
end
5 changes: 0 additions & 5 deletions spec/support/user.rb

This file was deleted.

0 comments on commit ea39c11

Please sign in to comment.