Skip to content

Instantly share code, notes, and snippets.

@kurko
Created October 21, 2015 23:15
Show Gist options
  • Save kurko/702c7f3b324682c04e7e to your computer and use it in GitHub Desktop.
Save kurko/702c7f3b324682c04e7e to your computer and use it in GitHub Desktop.
JSONAPI Deserialization
module JsonApi
class Relationships
def initialize(record, payload, id_attr: :uuid)
@record = record
@payload = payload
@id_attr = id_attr
end
def set_relationships(*relations_names)
relations_names = Array.wrap(relations_names)
return unless valid_relationship_payload?
relations_names.each do |name|
if relationship_exists?(name)
record.public_send(relationship_attr(name), get_relation_id(name))
end
end
end
private
attr_reader :record, :payload, :id_attr
def payload_relationships
payload[:data] && payload[:data][:relationships]
end
def get_relation_id(name)
if payload_relationships[name]
# passed_id is usually a uuid. Below, we get this e.g UUID and get the
# actual record. Then we keep the ID.
passed_id = payload_relationships[name][:data][:id]
klass = resource_class(name)
klass.public_send("find_by_#{id_attr}", passed_id).id
end
end
# resource_name is a symbol such as :category
def resource_class(resource_name)
resource_name.to_s.classify.constantize
rescue NameError # some classes might not exist
nil
end
def valid_relationship_payload?
payload_relationships.present?
end
def relationship_exists?(name)
record.respond_to?(relationship_attr(name))
end
def relationship_attr(name)
"#{name}_id="
end
end
end
require "rails_helper"
RSpec.describe JsonApi::Relationships do
let(:now) { "#{Time.now.utc.iso8601}" }
let(:record) { build(:entry, category: nil) }
let(:category) { create(:category) }
let(:payload) do
{
data: {
id: "uuid",
type: "entries",
attributes: {
name: "Supermarket",
amount: 12.34,
currency: "R$",
notes: "This is a note\nSecond line!",
date: now,
entry_type: "expense"
},
relationships: {
category: {
data: {
type: "categories",
id: category.uuid
}
}
}
}
}
end
subject { described_class.new(record, payload) }
describe "#set_relationships" do
it "set the relationships" do
expect(record.category).to eq(nil)
subject.set_relationships(:category, :non_existent)
expect(record.category).to eq(category)
end
context "no relationships" do
before do
payload[:data].delete(:relationships)
end
it "set the relationships" do
expect(record.category).to eq(nil)
subject.set_relationships(:category, :non_existent)
expect(record.category).to eq(nil)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment