Project

muesli

0.0
No commit activity in last 3 years
No release in over 3 years
Provides class-based recursive serialization of models into hashes with attribute whitelisting and conditionals for passing to views or as an API response.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

Muesli

Provides serialization of models into hashes with attribute whitelisting and authorization for passing to views or as an API response.

Why would you want this?

Well, just calling .to_json on a model exposes a lot of unfiltered information and many complex objects don't serialize into JSON very intuitively. Muesli provides serializers at the model level for conditionally whitelisting attributes and provides serializers at the attribute level for converting class types into the ideal data structure representation for your views or API responses.

ToDo Example

TodoSerializer

class TodoSerializer < Muesli::Serializers::Base
  @whitelisted_attributes = [
    :created_at,
    :due_at,
    :completed_at,
    :task,
    :priority
  ]
end

Todo

class Todo < ActiveRecord::Base
  def serializer
    TodoSerializer.new(self)
  end
end

Use

  irb(main):004:0> todo = Todo.first
  irb(main):005:0> todo.serializer.serialize

  => {:created_at => Tue, 28 June 2014 16:42:40 UTC +00:00, :due_at => Tue, 2 July 2014 16:42:40 UTC +00:00, :completed_at => nil, :task => "Mow the car.", :priority => 2}

CanCan Support (Valentine Example)

ValentineSerializer

You can do pretty much whatever you want by overriding the serialize method. I recommend doing so to interject the addition of conditional data. A perfect example is checking for authorization before including anything deemed private, like the name of your crush and their favorite candy (don't tell Steve.)

class ValentineSerializer < Muesli::Serializers::Base
  include Muesli::Adapters::CanCan

  @whitelisted_attributes = [
    :created_at,
    :codename
  ]

  def serialize
    serialized_hash = super

    # add private attributes only for the owner
    if can? :update, model
      serialized_hash.merge!({
        :crush          => CrushSerializer.new(model.crush).serialize,
        :favorite_candy => model.candy
      })
    end

    serialized_hash
  end
end

Valentine

class Valentine < ActiveRecord::Base
  def serializer
    ValentineSerializer.new(self)
  end
end

Use

  irb(main):004:0> valentine = Valentine.first
  irb(main):005:0> serializer = valentine.serializer
  irb(main):006:0> serializer.serialize

  => {:created_at => Tue, 10 February 2014 16:42:40 UTC +00:00, :codename => "Whisper Smileface"}

  irb(main):007:0> serializer.for_user(user).serialize

  => {:created_at => Tue, 10 February 2014 16:42:40 UTC +00:00, :codename => "Whisper Smileface", :crush_name => "Steve Buscemi", :favorite_candy => "Macaroon"}

I do recommend that you keep your serializers simple and flat. If you need nested structures or if your serializer is getting big - break it out into smaller serializers and delegate to them.

Custom Attribute Serializers

Let's say you use the Money gem. By default it serializes into a complicated, verbose structure. Maybe you just want it to serialize to a plain integer of cents. No problem. Create a Museli attribute serializer like so:

module Muesli
  module AttributeSerializers
    class Money
      def serialize
        @value.cents
      end
    end
  end
end

Now whenever Muesli encounters a Money class attribute it routes it through your serializer. Let's say you want to be a little more sophisticated. Money provides many methods. Let's say you want to return the fractional value and the currency as a string:

module Muesli
  module AttributeSerializers
    class Money < Base
      def serialize
        {
          :currency   => @value.currency_as_string,
          :fractional => @value.fractional
        }
      end
    end
  end
end

Or maybe you have Paperclip attachments you'd like each attachment to be serialized to its URL...

module Muesli
  module AttributeSerializers
    class Paperclip
      class Attachment < Base
        def serialize
          @value.present? ? @value.url : nil
        end
      end
    end
  end
end

You get the idea. If you want to be really fancy you can hook your models up to full-blown serialiers:

module Muesli
  module AttributeSerializers
    class Todo
      def serialize
        TodoSerializer.new(@value).serialize
      end
    end
  end
end

Now whenever Muesli encounters a Todo in your whitelisted attributes, it automatically uses the TodoSerializer to produce its serialization for the attribute. So that means, say if you have a notification model that has one todo, you can something like:

class Notification < Muesli::Serializers::Base
  @whitelisted_attributes = [
    :created_at,
    :read_at,
    :todo,
    :task
  ]
end

... and it'll just work. Neat!