class CrudMuffins::Rails::Adapter

ApplicationAdapter is the general structure of a serializer. It returns data through `as_json`.

We tried going through many different serializer libraries (FastJsonApi, ActiveModel Serializers, Roar, Representable, and Grape) and they all didn't do what we want. Basically, we want something that can magically convert snake_case to camelCase for us, to serve as a bridge between frontend and backend data representation when necessary, and to return errors when the model has them.

It turns out it was simpler to implement our own, which is what we've done here as a first pass.

Adapters are intended to wrap an ApplicationRecord, and should be able to delegate basic operations like `update` and `save` to the model, while still keeping it wrapped so it can return serialized data.

Attributes

model[R]

Public Class Methods

build(params) click to toggle source

makes a new model record with deserialized params and wraps it in the adapter

# File lib/crud-muffins-rails.rb, line 98
def self.build(params)
  new(model_class.new(deserialize(params)))
end
deserialize(params, _model = nil) click to toggle source

any logic needed to deserialize the params from the frontend, generally should be overridden

# File lib/crud-muffins-rails.rb, line 103
def self.deserialize(params, _model = nil)
  params
end
find(id, within: model_class) click to toggle source

general finder method that allows finding the record by ID within a scope, and wrapping it with the adapter

# File lib/crud-muffins-rails.rb, line 80
def self.find(id, within: model_class)
  new(within.find(id))
end
find_or_create_by(where, within: model_class) click to toggle source

similar to Rails find_or_create_by

# File lib/crud-muffins-rails.rb, line 85
def self.find_or_create_by(where, within: model_class)
  new(within.find_or_create_by(where))
end
model_class() click to toggle source

the ApplicationRecord or other model class that it is an adapter for

# File lib/crud-muffins-rails.rb, line 75
def self.model_class
  raise NotImplementedError
end
new(model) click to toggle source
# File lib/crud-muffins-rails.rb, line 110
def initialize(model)
  @model = model
end
where(*args) click to toggle source
# File lib/crud-muffins-rails.rb, line 93
def self.where(*args)
  Collection.new(model_class.where(*args), self)
end
within(within) click to toggle source
# File lib/crud-muffins-rails.rb, line 89
def self.within(within)
  Collection.new(within, self)
end

Public Instance Methods

as_json(*) click to toggle source
# File lib/crud-muffins-rails.rb, line 114
def as_json(*)
  {
    data: properties,
    type: type,
  }
end
errors() click to toggle source

JSON object of the model errors and their full message summaries

# File lib/crud-muffins-rails.rb, line 151
def errors
  {
    # Summary of all errors
    errors: model.errors.full_messages,
    # Errors associated with each attribute
    modelErrors: model.errors.messages.transform_keys { |key| key.to_s.camelize(:lower) }
  }
end
properties() click to toggle source

returns the serialized JSON object that will be passed to the frontend

# File lib/crud-muffins-rails.rb, line 126
def properties
  raise NotImplementedError
end
save() click to toggle source
# File lib/crud-muffins-rails.rb, line 134
def save
  model.save
end
serialize_props(*keys) click to toggle source

general helper to create a hash with the specified model attributes where their key names are lowerCamelCased

# File lib/crud-muffins-rails.rb, line 144
def serialize_props(*keys)
  keys.each_with_object({}) do |key, acc|
    acc[key.to_s.camelize(:lower).to_sym] = self.respond_to?(key) ? self.send(key) : model.send(key)
  end
end
type() click to toggle source
# File lib/crud-muffins-rails.rb, line 121
def type
  model.class.to_s
end
update(attributes) click to toggle source

updates the model with the deserialized attributes

# File lib/crud-muffins-rails.rb, line 139
def update(attributes)
  model.update(deserialize(attributes, model))
end
valid?() click to toggle source
# File lib/crud-muffins-rails.rb, line 130
def valid?
  model.valid?
end