ActiveModel::Serializer implementation and Rails hooks
Go to file
Benjamin Fleischer cdab6f2b8a The cache store needs to be the actually store, not e.g. :memory_store
Status quo in test app:
In Rails
    ActionController::Base.cache_store = :memory_store
and then AMS railtie does:
  ActiveModelSerializers.config.cache_store = config.action_controller.cache_store
then, in the Railtie
1. ActiveSupport.on_load(:action_controller) fires
  - ActiveModelSerializers.config.cache_store #=> nil
  - ActionController::Base.cache_store        #=> #<ActiveSupport::Cache::FileStore:0x007fe319256760...]
2. After set_configs fires
  - ActiveModelSerializers.config.cache_store #+> #<ActiveSupport::Cache::FileStore:0x007fe319256760 ,
3. Tests pass, but notice that we're using the FileStore, not memory store

When we change the config to the test app:
  ActionController::Base.cache_store = :memory_store
  config = Rails.configuration
  config.action_controller.cache_store = :memory_store
then, in the Railtie:
1. ActiveSupport.on_load(:action_controller) fires
  - ActiveModelSerializers.config.cache_store #=> nil
  - ActionController::Base.cache_store        #=> #ActiveSupport::Cache::MemoryStore entries=0, size=0, options={}>]
2. After set_configs fires
  - ActiveModelSerializers.config.cache_store #=> :memory_store
3. And we get a lot of failures:
  NoMethodError: undefined method `fetch' for :memory_store:Symbol

So, we see that when we set the ActionController::Base.cache_store
directly in our test app, we could set
ActiveModelSerializers.config.cache_store in the :action_controller load
hook, but that would never use the Rails config.

To fix the Rails config, we change the config to the test app:
  config = Rails.configuration
  config.action_controller.cache_store = :memory_store
and then AMS railtie does:
  ActiveModelSerializers.config.cache_store = ActiveSupport::Cache.lookup_store(config.action_controller.cache_store
  ActiveSupport.on_load(:action_controller) do
    ::ActiveModelSerializers.config.cache_store = cache_store
  end
then
1. After set_configs fires
  - ActiveModelSerializers.config.cache_store #=> <#ActiveSupport::Cache::MemoryStore, object_id 70207113611740
2. ActiveSupport.on_load(:action_controller) fires
  - ActionController::Base.cache_store        #=> <#ActiveSupport::Cache::MemoryStore, object_id 70207106279660
  - ActiveModelSerializers.config.cache_store #=> <#ActiveSupport::Cache::MemoryStore, object_id 70207106279660
    (notice the object_id changed)
3. And we get a failure:

  1) Failure:
  ActiveModelSerializers::CacheTest#test_associations_cache_when_updated
  [active_model_serializers/test/cache_test.rb:141]:
  --- expected
  +++ actual
  @@ -1 +1 @@
  -{:id=>"post", :title=>"New Post", :body=>"Body"}
  +{:id=>"post", :title=>"New Post", :body=>"Body", :comments=>[{:id=>2, :body=>"ZOMG A NEW COMMENT"}], :blog=>{:id=>999, :name=>"Custom blog"}, :author=>{:id=>"author", :name=>"Joao M. D. Moura"}}

If we take out the on_load(:action_controller) hook, we get a ton of
failures.  So clearly, our code expects the controller cache to be the
same as the serializer cache.

So, we make sure we use an on_load(:action_controller) hook that runs
after set_configs

And look at the test and see it is filled with direct calls to ActionController::Base.cache_store

    assert_equal(new_comment_serializer.attributes, ActionController::Base.cache_store.fetch(new_comment.cache_key))
    assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))

But that's not a problem in this case, since they're the same object.

For now, let's remove the :memory_store setting and use the default FileStore
2016-03-30 09:52:29 -05:00
.github Fix GitHub template formatting and spelling 2016-02-26 11:24:57 -07:00
bin Merge pull request #1588 from bf4/benchmark_revision_runner 2016-03-27 11:24:07 +02:00
docs architecture doc fix 2016-03-30 14:18:27 +01:00
lib The cache store needs to be the actually store, not e.g. :memory_store 2016-03-30 09:52:29 -05:00
test The cache store needs to be the actually store, not e.g. :memory_store 2016-03-30 09:52:29 -05:00
.gitignore Adds support for top-level links to JsonApi adapter 2016-02-03 10:16:22 -02:00
.rubocop_todo.yml Update rubocop todos 2016-03-08 22:32:34 +01:00
.rubocop.yml Setup benchmarking structure 2016-03-09 12:42:25 -06:00
.simplecov Update SimpleCov; remove compatibility patch 2016-02-09 20:59:31 -06:00
.travis.yml Replace -d by --debug in JRUBY_OPTS for travis 2016-03-19 01:30:16 +01:00
active_model_serializers.gemspec Remove annoying progress reporter 2016-03-26 19:27:33 -05:00
appveyor.yml add JRuby 9000 to appveyor.yml 2016-02-04 22:35:04 -06:00
CHANGELOG.md Move SerializableResource to ActiveModelSerializers namespace 2016-03-30 11:33:04 +02:00
CONTRIBUTING.md Simplify contributing.md; move details into GitHub templates 2016-02-26 10:43:52 -07:00
Gemfile Setup benchmarking structure 2016-03-09 12:42:25 -06:00
LICENSE.txt Generate a basic gem 2014-07-05 00:53:48 -04:00
Rakefile Allow devs to opt out of test warnings 2016-03-25 00:19:20 -05:00
README.md Issue stats don't actually update anymore 2016-03-12 20:07:34 -06:00

ActiveModelSerializers

Build Status Build Status Build status
Code Quality Code Quality codebeat Test Coverage
Issue Stats Pulse

Documentation

About

ActiveModelSerializers brings convention over configuration to your JSON generation.

ActiveModelSerializers works through two components: serializers and adapters.

Serializers describe which attributes and relationships should be serialized.

Adapters describe how attributes and relationships should be serialized.

SerializableResource co-ordinates the resource, Adapter and Serializer to produce the resource serialization. The serialization has the #as_json, #to_json and #serializable_hash methods used by the Rails JSON Renderer. (SerializableResource actually delegates these methods to the adapter.)

By default ActiveModelSerializers will use the Attributes Adapter. But we strongly advise you to use JsonApi Adapter, which follows 1.0 of the format specified in jsonapi.org/format. Check how to change the adapter in the sections below.

RELEASE CANDIDATE, PLEASE READ

This is the master branch of ActiveModelSerializers.

It will become the 0.10.0 release when it's ready. Currently this is a release candidate.

0.10.x is not backward compatible with 0.9.x nor 0.8.x.

0.10.x will be based on the 0.8.0 code, but with a more flexible architecture. We'd love your help. Learn how you can help here.

It is generally safe and recommended to use the master branch.

For more information, see the post 'The future of AMS'.

Installation

Add this line to your application's Gemfile:

gem 'active_model_serializers'

And then execute:

$ bundle

Getting Started

See Getting Started for the nuts and bolts.

More information is available in the Guides and High-level behavior.

Getting Help

If you find a bug, please report an Issue and see our contributing guide.

If you have a question, please post to Stack Overflow.

If you'd like to chat, we have a community slack.

Thanks!

High-level behavior

Given a serializable model:

# either
class SomeResource < ActiveRecord::Base
  # columns: title, body
end
# or
class SomeResource < ActiveModelSerializers::Model
  attr_accessor :title, :body
end

And initialized as:

resource = SomeResource.new(title: 'ActiveModelSerializers', body: 'Convention over configuration')

Given a serializer for the serializable model:

class SomeSerializer < ActiveModel::Serializer
  attribute :title, key: :name
  attributes :body
end

The model can be serialized as:

options = {}
serialization = SerializableResource.new(resource, options)
serialization.to_json
serialization.as_json

SerializableResource delegates to the adapter, which it builds as:

adapter_options = {}
adapter = Adapter.create(serializer, adapter_options)
adapter.to_json
adapter.as_json
adapter.serializable_hash

The adapter formats the serializer's attributes and associations (a.k.a. includes):

serializer_options = {}
serializer = SomeSerializer.new(resource, serializer_options)
serializer.attributes
serializer.associations

See ARCHITECTURE.md for more information.

Contributing

See CONTRIBUTING.md