From d1e46ec54cd1f20e2884477f9bc5e4f4fc9dbf44 Mon Sep 17 00:00:00 2001 From: Terminator3 Date: Thu, 20 Aug 2015 16:41:45 -0500 Subject: [PATCH 1/4] how to filter assocations added --- docs/README.md | 2 ++ docs/howto/filter_associations.md | 41 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 docs/howto/filter_associations.md diff --git a/docs/README.md b/docs/README.md index ddecb3e45..87251a552 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,6 +13,8 @@ This is the documentation of AMS, it's focused on the **0.10.x version.** - [How to add root key](howto/add_root_key.md) +- [Filtering Assocations](howto/filter_associations.md) + ## Getting Help If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new). diff --git a/docs/howto/filter_associations.md b/docs/howto/filter_associations.md new file mode 100644 index 000000000..1e9a74eff --- /dev/null +++ b/docs/howto/filter_associations.md @@ -0,0 +1,41 @@ +## Filtering Associations + +Say you have the following model: + +``` +class CategorySerializer < ActiveModel::Serializer + attributes :id, :name + has_many :products +end +``` + +For smaller apps, the rendering and loading of the serialized object (and its children) would be just fine. However, as your app scales, you might find yourself wanting the option of excluding associations in certain cases. + +You can do this by adding: + +``` +def filter(keys) + keys.delete :products if serialization_options[:products_disabled] +end +``` + +There are a few ways that you can invoke this. + +Rails Console / Testing: + +``` +@category = Category.create(name: "Sample Category") + +serializer = CategorySerializer.new(@category) +serializer.as_json(products_disabled: true) +``` + +Controller: + +``` +class CategoryController < ApplicationController + def index + @categories = Category.all + render json: @category, products_disabled: true + end +end \ No newline at end of file From ba846535363e0f84e36db4f9d9aef2f64416d65e Mon Sep 17 00:00:00 2001 From: Terminator3 Date: Thu, 20 Aug 2015 16:43:29 -0500 Subject: [PATCH 2/4] markdown fixes --- docs/howto/filter_associations.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/howto/filter_associations.md b/docs/howto/filter_associations.md index 1e9a74eff..af6de5433 100644 --- a/docs/howto/filter_associations.md +++ b/docs/howto/filter_associations.md @@ -2,7 +2,7 @@ Say you have the following model: -``` +```ruby class CategorySerializer < ActiveModel::Serializer attributes :id, :name has_many :products @@ -13,7 +13,7 @@ For smaller apps, the rendering and loading of the serialized object (and its ch You can do this by adding: -``` +```ruby def filter(keys) keys.delete :products if serialization_options[:products_disabled] end @@ -23,7 +23,7 @@ There are a few ways that you can invoke this. Rails Console / Testing: -``` +```ruby @category = Category.create(name: "Sample Category") serializer = CategorySerializer.new(@category) @@ -32,7 +32,7 @@ serializer.as_json(products_disabled: true) Controller: -``` +```ruby class CategoryController < ApplicationController def index @categories = Category.all From 53a2a0d99929e663f9536c879199ca0e8860e45f Mon Sep 17 00:00:00 2001 From: Pericles Theodorou Date: Sat, 12 Sep 2015 10:50:32 +0100 Subject: [PATCH 3/4] Documentation for serializing resources without render Fixed indentation in readme under 'using without render' Get rid of unnecessary instance variables, and implied dependencies. Fix typo in fieldset exception Updating wording on cache expiry in README Extended format for JSONAPI `include` option. Add lint tests for AR models. --- CHANGELOG.md | 1 + README.md | 21 ++++- docs/general/adapters.md | 2 + lib/active_model/serializer.rb | 1 + .../serializer/adapter/flatten_json.rb | 3 +- lib/active_model/serializer/adapter/json.rb | 14 ++-- .../serializer/adapter/json_api.rb | 56 +++++-------- lib/active_model/serializer/fieldset.rb | 2 +- lib/active_model/serializer/utils.rb | 35 ++++++++ .../action_controller/json_api/linked_test.rb | 15 ++-- test/active_record_test.rb | 9 +++ test/adapter/json_api/belongs_to_test.rb | 6 +- .../has_many_explicit_serializer_test.rb | 2 +- test/adapter/json_api/has_many_test.rb | 4 +- test/adapter/json_api/has_one_test.rb | 4 +- test/adapter/json_api/linked_test.rb | 12 +-- test/utils/include_args_to_hash_test.rb | 79 +++++++++++++++++++ 17 files changed, 197 insertions(+), 69 deletions(-) create mode 100644 lib/active_model/serializer/utils.rb create mode 100644 test/active_record_test.rb create mode 100644 test/utils/include_args_to_hash_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index b70c2e9a4..a5a8a744f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,3 +11,4 @@ * remove root key option and split JSON adapter [@joaomdmoura] * adds FlattenJSON as default adapter [@joaomdmoura] * adds support for `pagination links` at top level of JsonApi adapter [@bacarini] + * adds extended format for `include` option to JSONAPI adapter [@beauby] diff --git a/README.md b/README.md index 9cba3920d..c80fb30f3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ActiveModel::Serializer -[![Build Status](https://travis-ci.org/rails-api/active_model_serializers.svg)](https://travis-ci.org/rails-api/active_model_serializers) +[![Build Status](https://travis-ci.org/rails-api/active_model_serializers.svg)](https://travis-ci.org/rails-api/active_model_serializers) @@ -138,6 +138,23 @@ render json: @post, meta: { total: 10 }, meta_key: "custom_meta" `meta` will only be included in your response if you are using an Adapter that supports `root`, as JsonAPI and Json adapters, the default adapter (FlattenJson) doesn't have `root`. +### Using a serializer without `render` + +At times, you might want to use a serializer without rendering it to the view. For those cases, you can create an instance of `ActiveModel::SerializableResource` with +the resource you want to be serialized and call `.serializable_hash`. + +```ruby +def create + @message = current_user.messages.create!(message_params) + MessageCreationWorker.perform(serialized_message) + head 204 +end + +def serialized_message + ActiveModel::SerializableResource.new(@message).serializable_hash +end +``` + ### Overriding association methods If you want to override any association, you can use: @@ -283,7 +300,7 @@ The cache support is optimized to use the cached object in multiple request. An **[NOTE] Every object is individually cached.** -**[NOTE] The cache is automatically expired after update an object but it's not deleted.** +**[NOTE] The cache is automatically expired after an object is updated, but it's not deleted.** ```ruby cache(options = nil) # options: ```{key, expires_in, compress, force, race_condition_ttl}``` diff --git a/docs/general/adapters.md b/docs/general/adapters.md index b505a7f53..9a8e83a18 100644 --- a/docs/general/adapters.md +++ b/docs/general/adapters.md @@ -30,6 +30,8 @@ resources in the `"included"` member when the resource names are included in the render @posts, include: 'authors,comments' ``` +The format of the `include` option can be either a String composed of a comma-separated list of [relationship paths](http://jsonapi.org/format/#fetching-includes), an Array of Symbols and Hashes, or a mix of both. + ## Choosing an adapter If you want to use a specify a default adapter, such as JsonApi, you can change this in an initializer: diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 29acbabfe..2a3465cbe 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -10,6 +10,7 @@ class Serializer autoload :Lint autoload :Associations autoload :Fieldset + autoload :Utils include Configuration include Associations diff --git a/lib/active_model/serializer/adapter/flatten_json.rb b/lib/active_model/serializer/adapter/flatten_json.rb index 0c10f3e6e..bf0a690e7 100644 --- a/lib/active_model/serializer/adapter/flatten_json.rb +++ b/lib/active_model/serializer/adapter/flatten_json.rb @@ -1,7 +1,6 @@ class ActiveModel::Serializer::Adapter::FlattenJson < ActiveModel::Serializer::Adapter::Json def serializable_hash(options = {}) - super - @result + super.each_value.first end private diff --git a/lib/active_model/serializer/adapter/json.rb b/lib/active_model/serializer/adapter/json.rb index 2c0b6455c..f7b4fb84e 100644 --- a/lib/active_model/serializer/adapter/json.rb +++ b/lib/active_model/serializer/adapter/json.rb @@ -5,11 +5,11 @@ class ActiveModel::Serializer::Adapter::Json < ActiveModel::Serializer::Adapter def serializable_hash(options = nil) options ||= {} if serializer.respond_to?(:each) - @result = serializer.map { |s| FlattenJson.new(s).serializable_hash(options) } + result = serializer.map { |s| FlattenJson.new(s).serializable_hash(options) } else - @hash = {} + hash = {} - @core = cache_check(serializer) do + core = cache_check(serializer) do serializer.attributes(options) end @@ -19,13 +19,13 @@ def serializable_hash(options = nil) if serializer.respond_to?(:each) array_serializer = serializer - @hash[association.key] = array_serializer.map do |item| + hash[association.key] = array_serializer.map do |item| cache_check(item) do item.attributes(opts) end end else - @hash[association.key] = + hash[association.key] = if serializer && serializer.object cache_check(serializer) do serializer.attributes(options) @@ -35,10 +35,10 @@ def serializable_hash(options = nil) end end end - @result = @core.merge @hash + result = core.merge hash end - { root => @result } + { root => result } end def fragment_cache(cached_hash, non_cached_hash) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index f273fc65e..c1e5c94f1 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -7,11 +7,7 @@ def initialize(serializer, options = {}) super @hash = { data: [] } - @options[:include] ||= [] - if @options[:include].is_a?(String) - @options[:include] = @options[:include].split(',') - end - + @included = ActiveModel::Serializer::Utils.include_args_to_hash(@options[:include]) fields = options.delete(:fields) if fields @fieldset = ActiveModel::Serializer::Fieldset.new(fields, serializer.json_key) @@ -117,46 +113,36 @@ def relationships_for(serializer) end def included_for(serializer) - serializer.associations.flat_map { |assoc| _included_for(assoc.key, assoc.serializer) }.uniq + included = @included.flat_map do |inc| + association = serializer.associations.find { |assoc| assoc.key == inc.first } + _included_for(association.serializer, inc.second) if association + end + + included.uniq end - def _included_for(resource_name, serializer, parent = nil) + def _included_for(serializer, includes) if serializer.respond_to?(:each) - serializer.flat_map { |s| _included_for(resource_name, s, parent) }.uniq + serializer.flat_map { |s| _included_for(s, includes) }.uniq else return [] unless serializer && serializer.object - result = [] - resource_path = [parent, resource_name].compact.join('.') - - if include_assoc?(resource_path) - primary_data = primary_data_for(serializer, @options) - relationships = relationships_for(serializer) - primary_data[:relationships] = relationships if relationships.any? - result.push(primary_data) - end - if include_nested_assoc?(resource_path) - non_empty_associations = serializer.associations.select(&:serializer) + primary_data = primary_data_for(serializer, @options) + relationships = relationships_for(serializer) + primary_data[:relationships] = relationships if relationships.any? + + included = [primary_data] - non_empty_associations.each do |association| - result.concat(_included_for(association.key, association.serializer, resource_path)) - result.uniq! + includes.each do |inc| + association = serializer.associations.find { |assoc| assoc.key == inc.first } + if association + included.concat(_included_for(association.serializer, inc.second)) + included.uniq! end end - result - end - end - - def include_assoc?(assoc) - check_assoc("#{assoc}$") - end - def include_nested_assoc?(assoc) - check_assoc("#{assoc}.") - end - - def check_assoc(assoc) - @options[:include].any? { |s| s.match(/^#{assoc.gsub('.', '\.')}/) } + included + end end def add_links(options) diff --git a/lib/active_model/serializer/fieldset.rb b/lib/active_model/serializer/fieldset.rb index 935aea81a..9d1f8ae38 100644 --- a/lib/active_model/serializer/fieldset.rb +++ b/lib/active_model/serializer/fieldset.rb @@ -26,7 +26,7 @@ def parsed_fields raw_fields.inject({}) { |h, (k, v)| h[k.to_sym] = v.map(&:to_sym); h } elsif raw_fields.is_a?(Array) if root.nil? - raise ArgumentError, 'The root argument must be specified if the fileds argument is an array.' + raise ArgumentError, 'The root argument must be specified if the fields argument is an array.' end hash = {} hash[root.to_sym] = raw_fields.map(&:to_sym) diff --git a/lib/active_model/serializer/utils.rb b/lib/active_model/serializer/utils.rb new file mode 100644 index 000000000..689f48ca5 --- /dev/null +++ b/lib/active_model/serializer/utils.rb @@ -0,0 +1,35 @@ +module ActiveModel::Serializer::Utils + module_function + + # Translates a comma separated list of dot separated paths (JSONAPI format) into a Hash. + # Example: `'posts.author, posts.comments.upvotes, posts.comments.author'` would become `{ posts: { author: {}, comments: { author: {}, upvotes: {} } } }`. + # + # @param [String] included + # @return [Hash] a Hash representing the same tree structure + def include_string_to_hash(included) + included.delete(' ').split(',').inject({}) do |hash, path| + hash.deep_merge!(path.split('.').reverse_each.inject({}) { |a, e| { e.to_sym => a } }) + end + end + + # Translates the arguments passed to the include option into a Hash. The format can be either + # a String (see #include_string_to_hash), an Array of Symbols and Hashes, or a mix of both. + # Example: `posts: [:author, comments: [:author, :upvotes]]` would become `{ posts: { author: {}, comments: { author: {}, upvotes: {} } } }`. + # + # @param [Symbol, Hash, Array, String] included + # @return [Hash] a Hash representing the same tree structure + def include_args_to_hash(included) + case included + when Symbol + { included => {} } + when Hash + included.each_with_object({}) { |(key, value), hash| hash[key] = include_args_to_hash(value) } + when Array + included.inject({}) { |a, e| a.merge!(include_args_to_hash(e)) } + when String + include_string_to_hash(included) + else + {} + end + end +end diff --git a/test/action_controller/json_api/linked_test.rb b/test/action_controller/json_api/linked_test.rb index fc0c87939..ba317e212 100644 --- a/test/action_controller/json_api/linked_test.rb +++ b/test/action_controller/json_api/linked_test.rb @@ -43,29 +43,29 @@ def render_resource_without_include def render_resource_with_include setup_post - render json: @post, include: 'author', adapter: :json_api + render json: @post, include: [:author], adapter: :json_api end def render_resource_with_nested_include setup_post - render json: @post, include: 'comments.author', adapter: :json_api + render json: @post, include: [comments: [:author]], adapter: :json_api end def render_resource_with_nested_has_many_include setup_post - render json: @post, include: ['author', 'author.roles'], adapter: :json_api + render json: @post, include: 'author.roles', adapter: :json_api end def render_resource_with_missing_nested_has_many_include setup_post @post.author = @author2 # author2 has no roles. - render json: @post, include: 'author,author.roles', adapter: :json_api + render json: @post, include: [author: [:roles]], adapter: :json_api end def render_collection_with_missing_nested_has_many_include setup_post @post.author = @author2 - render json: [@post, @post2], include: 'author,author.roles', adapter: :json_api + render json: [@post, @post2], include: [author: [:roles]], adapter: :json_api end def render_collection_without_include @@ -75,7 +75,7 @@ def render_collection_without_include def render_collection_with_include setup_post - render json: [@post], include: %w(author comments), adapter: :json_api + render json: [@post], include: 'author, comments', adapter: :json_api end end @@ -141,8 +141,7 @@ def test_render_resource_with_nested_include get :render_resource_with_nested_include response = JSON.parse(@response.body) assert response.key? 'included' - assert_equal 1, response['included'].size - assert_equal 'Anonymous', response['included'].first['attributes']['name'] + assert_equal 3, response['included'].size end def test_render_collection_without_include diff --git a/test/active_record_test.rb b/test/active_record_test.rb new file mode 100644 index 000000000..70932b38c --- /dev/null +++ b/test/active_record_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class ActiveRecordTest < Minitest::Test + include ActiveModel::Serializer::Lint::Tests + + def setup + @resource = ARModels::Post.new + end +end diff --git a/test/adapter/json_api/belongs_to_test.rb b/test/adapter/json_api/belongs_to_test.rb index 5cb6cdeb0..5bfdc52bf 100644 --- a/test/adapter/json_api/belongs_to_test.rb +++ b/test/adapter/json_api/belongs_to_test.rb @@ -38,7 +38,7 @@ def test_includes_post_id end def test_includes_linked_post - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'post') + @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post]) expected = [{ id: '42', type: 'posts', @@ -56,7 +56,7 @@ def test_includes_linked_post end def test_limiting_linked_post_fields - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'post', fields: { post: [:title] }) + @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post], fields: { post: [:title] }) expected = [{ id: '42', type: 'posts', @@ -108,7 +108,7 @@ def test_include_type_for_association_when_different_than_name def test_include_linked_resources_with_type_name serializer = BlogSerializer.new(@blog) - adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, include: %w(writer articles)) + adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, include: [:writer, :articles]) linked = adapter.serializable_hash[:included] expected = [ { diff --git a/test/adapter/json_api/has_many_explicit_serializer_test.rb b/test/adapter/json_api/has_many_explicit_serializer_test.rb index aedde98c1..5c53fa01a 100644 --- a/test/adapter/json_api/has_many_explicit_serializer_test.rb +++ b/test/adapter/json_api/has_many_explicit_serializer_test.rb @@ -24,7 +24,7 @@ def setup @serializer = PostPreviewSerializer.new(@post) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new( @serializer, - include: %w(comments author) + include: [:comments, :author] ) end diff --git a/test/adapter/json_api/has_many_test.rb b/test/adapter/json_api/has_many_test.rb index 277380a01..699126c23 100644 --- a/test/adapter/json_api/has_many_test.rb +++ b/test/adapter/json_api/has_many_test.rb @@ -42,7 +42,7 @@ def test_includes_comment_ids end def test_includes_linked_comments - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'comments') + @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:comments]) expected = [{ id: '1', type: 'comments', @@ -68,7 +68,7 @@ def test_includes_linked_comments end def test_limit_fields_of_linked_comments - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'comments', fields: { comment: [:id] }) + @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:comments], fields: { comment: [:id] }) expected = [{ id: '1', type: 'comments', diff --git a/test/adapter/json_api/has_one_test.rb b/test/adapter/json_api/has_one_test.rb index 3fb2bf5fa..29582ddf9 100644 --- a/test/adapter/json_api/has_one_test.rb +++ b/test/adapter/json_api/has_one_test.rb @@ -28,7 +28,7 @@ def setup @virtual_value = VirtualValue.new(id: 1) @serializer = AuthorSerializer.new(@author) - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'bio,posts') + @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:bio, :posts]) end def test_includes_bio_id @@ -38,7 +38,7 @@ def test_includes_bio_id end def test_includes_linked_bio - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'bio') + @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:bio]) expected = [ { diff --git a/test/adapter/json_api/linked_test.rb b/test/adapter/json_api/linked_test.rb index 261c001a8..7b4b43f1d 100644 --- a/test/adapter/json_api/linked_test.rb +++ b/test/adapter/json_api/linked_test.rb @@ -43,11 +43,11 @@ def test_include_multiple_posts_and_linked_array serializer = ArraySerializer.new([@first_post, @second_post]) adapter = ActiveModel::Serializer::Adapter::JsonApi.new( serializer, - include: ['author', 'author.bio', 'comments'] + include: [:comments, author: [:bio]] ) alt_adapter = ActiveModel::Serializer::Adapter::JsonApi.new( serializer, - include: 'author,author.bio,comments' + include: [:comments, author: [:bio]] ) expected = { @@ -153,11 +153,11 @@ def test_include_multiple_posts_and_linked serializer = BioSerializer.new @bio1 adapter = ActiveModel::Serializer::Adapter::JsonApi.new( serializer, - include: ['author', 'author.posts'] + include: [author: [:posts]] ) alt_adapter = ActiveModel::Serializer::Adapter::JsonApi.new( serializer, - include: 'author,author.posts' + include: [author: [:posts]] ) expected = [ @@ -224,7 +224,7 @@ def test_multiple_references_to_same_resource serializer = ArraySerializer.new([@first_comment, @second_comment]) adapter = ActiveModel::Serializer::Adapter::JsonApi.new( serializer, - include: ['post'] + include: [:post] ) expected = [ @@ -257,7 +257,7 @@ def test_nil_link_with_specified_serializer serializer = PostPreviewSerializer.new(@first_post) adapter = ActiveModel::Serializer::Adapter::JsonApi.new( serializer, - include: ['author'] + include: [:author] ) expected = { diff --git a/test/utils/include_args_to_hash_test.rb b/test/utils/include_args_to_hash_test.rb new file mode 100644 index 000000000..deb87f1cc --- /dev/null +++ b/test/utils/include_args_to_hash_test.rb @@ -0,0 +1,79 @@ +require 'test_helper' + +module ActiveModel + class Serializer + module Utils + class IncludeArgsToHashTest < Minitest::Test + def test_nil + input = nil + expected = {} + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_empty_string + input = '' + expected = {} + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_single_string + input = 'author' + expected = { author: {} } + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_multiple_strings + input = 'author,comments' + expected = { author: {}, comments: {} } + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_multiple_strings_with_space + input = 'author, comments' + expected = { author: {}, comments: {} } + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_nested_string + input = 'posts.author' + expected = { posts: { author: {} } } + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_multiple_nested_string + input = 'posts.author,posts.comments.author,comments' + expected = { posts: { author: {}, comments: { author: {} } }, comments: {} } + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_empty_array + input = [] + expected = {} + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_simple_array + input = [:comments, :author] + expected = { author: {}, comments: {} } + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + + def test_nested_array + input = [:comments, posts: [:author, comments: [:author]]] + expected = { posts: { author: {}, comments: { author: {} } }, comments: {} } + actual = ActiveModel::Serializer::Utils.include_args_to_hash(input) + assert_equal(expected, actual) + end + end + end + end +end From 1cdb32d9a73ccbf2716081811691a7b9b6811c3f Mon Sep 17 00:00:00 2001 From: Terminator3 Date: Wed, 26 Aug 2015 15:49:59 -0500 Subject: [PATCH 4/4] modifications to tutorial punctuation fixes as json addition eliminated redundancy minor tweaks README fix modifications to tutorial punctuation fixes as json addition minor tweaks modifications to tutorial punctuation fixes as json addition eliminated redundancy minor tweaks modifications to tutorial as json addition eliminated redundancy minor tweaks final edits final final changes --- docs/README.md | 3 +- docs/howto/filter_associations.md | 41 --------------------------- docs/howto/outside_controller_use.md | 42 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 43 deletions(-) delete mode 100644 docs/howto/filter_associations.md create mode 100644 docs/howto/outside_controller_use.md diff --git a/docs/README.md b/docs/README.md index ae7b58d0b..96ca05fed 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,8 +14,7 @@ This is the documentation of AMS, it's focused on the **0.10.x version.** - [How to add root key](howto/add_root_key.md) - [How to add pagination links](howto/add_pagination_links.md) - -- [Filtering Assocations](howto/filter_associations.md) +- [Use AMS Outside A Controller](howto/outside_controller_use.md) ## Getting Help diff --git a/docs/howto/filter_associations.md b/docs/howto/filter_associations.md deleted file mode 100644 index af6de5433..000000000 --- a/docs/howto/filter_associations.md +++ /dev/null @@ -1,41 +0,0 @@ -## Filtering Associations - -Say you have the following model: - -```ruby -class CategorySerializer < ActiveModel::Serializer - attributes :id, :name - has_many :products -end -``` - -For smaller apps, the rendering and loading of the serialized object (and its children) would be just fine. However, as your app scales, you might find yourself wanting the option of excluding associations in certain cases. - -You can do this by adding: - -```ruby -def filter(keys) - keys.delete :products if serialization_options[:products_disabled] -end -``` - -There are a few ways that you can invoke this. - -Rails Console / Testing: - -```ruby -@category = Category.create(name: "Sample Category") - -serializer = CategorySerializer.new(@category) -serializer.as_json(products_disabled: true) -``` - -Controller: - -```ruby -class CategoryController < ApplicationController - def index - @categories = Category.all - render json: @category, products_disabled: true - end -end \ No newline at end of file diff --git a/docs/howto/outside_controller_use.md b/docs/howto/outside_controller_use.md new file mode 100644 index 000000000..e74258c08 --- /dev/null +++ b/docs/howto/outside_controller_use.md @@ -0,0 +1,42 @@ +## Using AMS Outside Of A Controller + +### Serializing a resource + +In AMS versions 0.10 or later, serializing resources outside of the controller context is fairly simple: + +```ruby +# Create our resource +post = Post.create(title: "Sample post", body: "I love Active Model Serializers!") + +# Optional options parameters +options = {} + +# Create a serializable resource instance +serializable_resource = ActiveModel::SerializableResource.new(post, options) + +# Convert your resource into json +model_json = serializable_resource.as_json +``` + +### Retrieving a Resource's Active Model Serializer + +If you want to retrieve a serializer for a specific resource, you can do the following: + +```ruby +# Create our resource +post = Post.create(title: "Another Example", body: "So much fun.") + +# Optional options parameters +options = {} + +# Retrieve the default serializer for posts +serializer = ActiveModel::Serializer.serializer_for(post, options) +``` + +You could also retrieve the serializer via: + +```ruby +ActiveModel::SerializableResource.new(post, options).serializer +``` + +Both approaches will return an instance, if any, of the resource's serializer. \ No newline at end of file