mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-23 06:16:50 +00:00
Merge branch 'rewrite'
This commit is contained in:
commit
c65d387705
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,7 +3,7 @@
|
||||
.bundle
|
||||
.config
|
||||
.yardoc
|
||||
Gemfile.lock
|
||||
*.lock
|
||||
InstalledFiles
|
||||
_yardoc
|
||||
coverage
|
||||
|
||||
@ -6,10 +6,8 @@ rvm:
|
||||
- rbx-19mode
|
||||
gemfile:
|
||||
- Gemfile
|
||||
- Gemfile.rails3
|
||||
- Gemfile.edge
|
||||
matrix:
|
||||
allow_failures:
|
||||
- gemfile: Gemfile.edge
|
||||
notifications:
|
||||
email: false
|
||||
campfire:
|
||||
|
||||
58
CHANGELOG.md
58
CHANGELOG.md
@ -1,46 +1,20 @@
|
||||
# UNRELEASED
|
||||
# VERSION 0.9.0.pre
|
||||
|
||||
* ActiveModel::Serializable was created it has the shared code between
|
||||
AM::Serializer and AM::ArraySerializer. Basically enable objects to be
|
||||
serializable by implementing an options method to handle the options
|
||||
of the serialization and a serialize method that returns an object to
|
||||
be converted to json by the module. This also removes duplicate code.
|
||||
https://github.com/rails-api/active_model_serializers/commit/6c6bc8872d3b0f040a200854fa5530a775824dbf
|
||||
* The following methods were removed
|
||||
- Model#active\_model\_serializer
|
||||
- Serializer#include!
|
||||
- Serializer#include?
|
||||
- Serializer#attr\_disabled=
|
||||
- Serializer#cache
|
||||
- Serializer#perform\_caching
|
||||
- Serializer#schema (needs more discussion)
|
||||
- Serializer#attribute
|
||||
- Serializer#include\_#{name}? (filter method added)
|
||||
- Serializer#attributes (took a hash)
|
||||
|
||||
* ActiveModel::Serializer::Caching module was created it enables
|
||||
Serializers to be able to cache to\_json and serialize calls. This
|
||||
also helps removing duplicate code.
|
||||
https://github.com/rails-api/active_model_serializers/commit/3e27110df78696ac48cafd1568f72216f348a188
|
||||
|
||||
* We got rid of the Association.refine method which generated
|
||||
subclasses.
|
||||
https://github.com/rails-api/active_model_serializers/commit/24923722d4f215c7cfcdf553fd16582e28e3801b
|
||||
|
||||
* Associations doesn't know anymore about the source serializer.
|
||||
That didn't make any sense.
|
||||
https://github.com/rails-api/active_model_serializers/commit/2252e8fe6dbf45660c6a35f35e2423792f2c3abf
|
||||
https://github.com/rails-api/active_model_serializers/commit/87eadd09b9a988bc1d9b30d9a501ef7e3fc6bb87
|
||||
https://github.com/rails-api/active_model_serializers/commit/79a6e13e8f7fae2eb4f48e83a9633e74beb6739e
|
||||
|
||||
* Passing options[:hash] is not public API of include!. That was
|
||||
removed.
|
||||
https://github.com/rails-api/active_model_serializers/commit/5cbf9317051002a32c90c3f995b8b2f126f70d0c
|
||||
|
||||
* ActiveModel::Serializer::Associations::Config is now
|
||||
ActiveModel::Serializer::Association but it's an internal
|
||||
thing so shouldn't bother.
|
||||
ActiveModel::Serializer::Associations::Has\* are now
|
||||
ActiveModel::Serializer::Association::Has\* and inherit from
|
||||
ActiveModel::Serializer::Association
|
||||
https://github.com/rails-api/active_model_serializers/commit/f5de334ddf1f3b9764d914a717311532021785d2
|
||||
https://github.com/rails-api/active_model_serializers/commit/3dd422d99e8c57f113880da34f6abe583c4dadf9
|
||||
|
||||
* serialize\_ids call methods on the corresponding serializer if they
|
||||
are defined, instead of talking directly with the serialized object.
|
||||
Serializers are decorators so we shouldn't talk directly with
|
||||
serialized objects.
|
||||
|
||||
* Array items are not wrapped anymore in root element.
|
||||
* The following things were added
|
||||
- Serializer#filter method
|
||||
- SETTINGS object
|
||||
|
||||
* Remove support for ruby 1.8 versions.
|
||||
|
||||
@ -107,7 +81,7 @@
|
||||
* Allow serialization_scope to be disabled with serialization_scope nil
|
||||
* Array serializer should support pure ruby objects besides serializers
|
||||
|
||||
# VERSION 0.5.0 (May 16, 2012)
|
||||
# VERSION 0.5.0
|
||||
|
||||
* First tagged version
|
||||
* Changes generators to always generate an ApplicationSerializer
|
||||
|
||||
6
Gemfile
6
Gemfile
@ -3,4 +3,8 @@ source 'https://rubygems.org'
|
||||
# Specify gem dependencies in active_model_serializers.gemspec
|
||||
gemspec
|
||||
|
||||
gem "coveralls", require: false
|
||||
gem 'sqlite3'
|
||||
gem 'coveralls', :require => false
|
||||
gem 'simplecov', :require => false
|
||||
|
||||
gem 'rails', "~> 4.0.0"
|
||||
|
||||
10
Gemfile.edge
10
Gemfile.edge
@ -1,9 +1,13 @@
|
||||
source 'http://rubygems.org'
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
|
||||
gem 'sqlite3'
|
||||
gem 'coveralls', :require => false
|
||||
gem 'simplecov', :require => false
|
||||
|
||||
# Use Rails master
|
||||
gem 'rails', github: 'rails/rails'
|
||||
|
||||
# Current dependencies of edge rails
|
||||
gem 'journey', github: 'rails/journey'
|
||||
gem 'activerecord-deprecated_finders' , github: 'rails/activerecord-deprecated_finders'
|
||||
gem 'arel', github: 'rails/arel'
|
||||
|
||||
11
Gemfile.rails3
Normal file
11
Gemfile.rails3
Normal file
@ -0,0 +1,11 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Specify gem dependencies in active_model_serializers.gemspec
|
||||
gemspec
|
||||
|
||||
gem 'sqlite3'
|
||||
gem 'coveralls', :require => false
|
||||
gem 'simplecov', :require => false
|
||||
|
||||
gem 'minitest', '~> 4.0'
|
||||
gem 'rails', '~> 3.2'
|
||||
109
README.md
109
README.md
@ -3,8 +3,9 @@
|
||||
# Purpose
|
||||
|
||||
The purpose of `ActiveModel::Serializers` is to provide an object to
|
||||
encapsulate serialization of `ActiveModel` objects, including `ActiveRecord`
|
||||
objects.
|
||||
encapsulate serialization of objects which respond to
|
||||
read\_attribute\_for\_serialization like ActiveModel ones and including
|
||||
`ActiveRecord` objects.
|
||||
|
||||
Serializers know about both a model and the `current_user`, so you can
|
||||
customize serialization based upon whether a user is authorized to see the
|
||||
@ -55,17 +56,11 @@ the serializer generator:
|
||||
$ rails g serializer post
|
||||
```
|
||||
|
||||
### Support for POROs and other ORMs.
|
||||
### Support for POROs
|
||||
|
||||
Currently `ActiveModel::Serializers` adds serialization support to all models
|
||||
that descend from `ActiveRecord` or include `Mongoid::Document`. If you are
|
||||
using another ORM, or if you are using objects that are `ActiveModel`
|
||||
compliant but do not descend from `ActiveRecord` or include
|
||||
`Mongoid::Document`, you must add an include statement for
|
||||
`ActiveModel::SerializerSupport` to make models serializable. If you
|
||||
also want to make collections serializable, you should include
|
||||
`ActiveModel::ArraySerializerSupport` into your ORM's
|
||||
relation/criteria class.
|
||||
Currently `ActiveModel::Serializers` expects objects to implement
|
||||
read\_attribute\_for\_serialization. That's all you need to do to have
|
||||
your POROs supported.
|
||||
|
||||
# ActiveModel::Serializer
|
||||
|
||||
@ -92,19 +87,8 @@ This also works with `respond_with`, which uses `to_json` under the hood. Also
|
||||
note that any options passed to `render :json` will be passed to your
|
||||
serializer and available as `@options` inside.
|
||||
|
||||
To specify a custom serializer for an object, there are 2 options:
|
||||
|
||||
#### 1. Specify the serializer in your model:
|
||||
|
||||
```ruby
|
||||
class Post < ActiveRecord::Base
|
||||
def active_model_serializer
|
||||
FancyPostSerializer
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
#### 2. Specify the serializer when you render the object:
|
||||
To specify a custom serializer for an object, you can specify the
|
||||
serializer when you render the object:
|
||||
|
||||
```ruby
|
||||
render json: @post, serializer: FancyPostSerializer
|
||||
@ -267,49 +251,44 @@ class VersionSerializer < ActiveModel::Serializer
|
||||
end
|
||||
```
|
||||
|
||||
You can also access the `current_user` method, which provides an
|
||||
You can also access the `scope` method, which provides an
|
||||
authorization context to your serializer. By default, the context
|
||||
is the current user of your application, but this
|
||||
[can be customized](#customizing-scope).
|
||||
|
||||
Serializers will check for the presence of a method named
|
||||
`include_[ATTRIBUTE]?` to determine whether a particular attribute should be
|
||||
included in the output. This is typically used to customize output
|
||||
based on `current_user`. For example:
|
||||
Serializers provides a method named `filter` used to determine what
|
||||
attributes and associations should be included in the output. This is
|
||||
typically used to customize output based on `current_user`. For example:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body, :author
|
||||
|
||||
def include_author?
|
||||
current_user.admin?
|
||||
def filter(keys)
|
||||
if scope.admin?
|
||||
keys
|
||||
else
|
||||
keys - [:author]
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
The type of a computed attribute (like :full_name above) is not easily
|
||||
calculated without some sophisticated static code analysis. To specify the
|
||||
type of a computed attribute:
|
||||
|
||||
```ruby
|
||||
class PersonSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name, {full_name: :string}
|
||||
|
||||
def full_name
|
||||
"#{object.first_name} #{object.last_name}"
|
||||
end
|
||||
end
|
||||
```
|
||||
And it's also safe to mutate keys argument by doing keys.delete(:author)
|
||||
in case you want to avoid creating two extra arrays.
|
||||
|
||||
If you would like the key in the outputted JSON to be different from its name
|
||||
in ActiveRecord, you can use the `:key` option to customize it:
|
||||
in ActiveRecord, you can declare the attribute with the different name
|
||||
and redefine that method:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :body
|
||||
# look up subject on the model, but use title in the JSON
|
||||
def title
|
||||
object.subject
|
||||
end
|
||||
|
||||
# look up :subject on the model, but use +title+ in the JSON
|
||||
attribute :subject, key: :title
|
||||
attributes :id, :body, :title
|
||||
has_many :comments
|
||||
end
|
||||
```
|
||||
@ -360,7 +339,7 @@ class PersonSerializer < ActiveModel::Serializer
|
||||
|
||||
def attributes
|
||||
hash = super
|
||||
if current_user.admin?
|
||||
if scope.admin?
|
||||
hash["ssn"] = object.ssn
|
||||
hash["secret"] = object.mothers_maiden_name
|
||||
end
|
||||
@ -405,23 +384,23 @@ class PostSerializer < ActiveModel::Serializer
|
||||
end
|
||||
```
|
||||
|
||||
Also, as with attributes, serializers will check for the presence
|
||||
of a method named `include_[ASSOCIATION]?` to determine whether a particular association
|
||||
should be included in the output. For example:
|
||||
Also, as with attributes, serializers will execute a filter method to
|
||||
determine which associations should be included in the output. For
|
||||
example:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body
|
||||
has_many :comments
|
||||
|
||||
def include_comments?
|
||||
!object.comments_disabled?
|
||||
def filter(keys)
|
||||
keys.delete :comments if object.comments_disabled?
|
||||
keys
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
If you would like lower-level control of association serialization, you can
|
||||
override `include_associations!` to specify which associations should be included:
|
||||
Or ...
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
@ -429,9 +408,10 @@ class PostSerializer < ActiveModel::Serializer
|
||||
has_one :author
|
||||
has_many :comments
|
||||
|
||||
def include_associations!
|
||||
include! :author if current_user.admin?
|
||||
include! :comments unless object.comments_disabled?
|
||||
def filter(keys)
|
||||
keys.delete :author unless current_user.admin?
|
||||
keys.delete :comments if object.comments_disabled?
|
||||
keys
|
||||
end
|
||||
end
|
||||
```
|
||||
@ -445,6 +425,9 @@ You may also use the `:serializer` option to specify a custom serializer class a
|
||||
|
||||
Serializers are only concerned with multiplicity, and not ownership. `belongs_to` ActiveRecord associations can be included using `has_one` in your serializer.
|
||||
|
||||
NOTE: polymorphic was removed because was only supported for has\_one
|
||||
associations and is in the TODO list of the project.
|
||||
|
||||
## Embedding Associations
|
||||
|
||||
By default, associations will be embedded inside the serialized object. So if
|
||||
@ -635,7 +618,7 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
```
|
||||
|
||||
The above example will also change the scope name from `current_user` to
|
||||
The above example will also change the scope from `current_user` to
|
||||
`current_admin`.
|
||||
|
||||
Please note that, until now, `serialization_scope` doesn't accept a second
|
||||
@ -678,6 +661,10 @@ that query, only the `show` action will.
|
||||
|
||||
## Caching
|
||||
|
||||
NOTE: This functionality was removed from AMS and it's in the TODO list.
|
||||
We need to re-think and re-design the caching strategy for the next
|
||||
version of AMS.
|
||||
|
||||
To cache a serializer, call `cached` and define a `cache_key` method:
|
||||
|
||||
```ruby
|
||||
|
||||
7
Rakefile
7
Rakefile
@ -10,9 +10,4 @@ Rake::TestTask.new(:test) do |t|
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Benchmark'
|
||||
task :bench do
|
||||
load 'bench/perf.rb'
|
||||
end
|
||||
|
||||
task default: :test
|
||||
task :default => :test
|
||||
|
||||
@ -4,15 +4,15 @@ $:.unshift File.expand_path("../lib", __FILE__)
|
||||
require "active_model/serializer/version"
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.authors = ["José Valim", "Yehuda Katz"]
|
||||
gem.email = ["jose.valim@gmail.com", "wycats@gmail.com"]
|
||||
gem.authors = ["José Valim", "Yehuda Katz", "Santiago Pastorino"]
|
||||
gem.email = ["jose.valim@gmail.com", "wycats@gmail.com", "santiago@wyeworks.com"]
|
||||
gem.description = %q{Making it easy to serialize models for client-side use}
|
||||
gem.summary = %q{Bringing consistency and object orientation to model serialization. Works great for client-side MVC frameworks!}
|
||||
gem.homepage = "https://github.com/rails-api/active_model_serializers"
|
||||
|
||||
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||
gem.files = `git ls-files`.split("\n")
|
||||
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
||||
gem.files = Dir['README.md', 'CHANGELOG.md', 'CONTRIBUTING.md', 'DESIGN.textile', 'MIT-LICENSE', 'lib/**/*', 'test/**/*']
|
||||
gem.test_files = Dir['test/**/*']
|
||||
|
||||
gem.name = "active_model_serializers"
|
||||
gem.require_paths = ["lib"]
|
||||
gem.version = ActiveModel::Serializer::VERSION
|
||||
@ -20,9 +20,5 @@ Gem::Specification.new do |gem|
|
||||
gem.required_ruby_version = ">= 1.9.3"
|
||||
|
||||
gem.add_dependency "activemodel", ">= 3.2"
|
||||
|
||||
gem.add_development_dependency "rails", ">= 3.2"
|
||||
gem.add_development_dependency "pry"
|
||||
gem.add_development_dependency "simplecov"
|
||||
gem.add_development_dependency "coveralls"
|
||||
end
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
require "active_model_serializers"
|
||||
require "active_support/json"
|
||||
require "benchmark"
|
||||
|
||||
class User < Struct.new(:id,:name,:age,:about)
|
||||
include ActiveModel::SerializerSupport
|
||||
|
||||
def fast_hash
|
||||
h = {
|
||||
id: read_attribute_for_serialization(:id),
|
||||
name: read_attribute_for_serialization(:name),
|
||||
about: read_attribute_for_serialization(:about)
|
||||
}
|
||||
h[:age] = read_attribute_for_serialization(:age) if age > 18
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
class UserSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :age, :about
|
||||
|
||||
def include_age?
|
||||
object.age > 18
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
u = User.new(1, "sam", 10, "about")
|
||||
s = UserSerializer.new(u)
|
||||
|
||||
n = 100000
|
||||
|
||||
Benchmark.bmbm {|x|
|
||||
x.report("init") { n.times { UserSerializer.new(u) } }
|
||||
x.report("fast_hash") { n.times { u.fast_hash } }
|
||||
x.report("attributes") { n.times { UserSerializer.new(u).attributes } }
|
||||
x.report("serializable_hash") { n.times { UserSerializer.new(u).serializable_hash } }
|
||||
}
|
||||
|
||||
|
||||
19
cruft.md
19
cruft.md
@ -1,19 +0,0 @@
|
||||
As of Ruby 1.9.3, it is impossible to dynamically generate a Symbol
|
||||
through interpolation without generating garbage. Theoretically, Ruby
|
||||
should be able to take care of this by building up the String in C and
|
||||
interning the C String.
|
||||
|
||||
Because of this, we avoid generating dynamic Symbols at runtime. For
|
||||
example, instead of generating the instrumentation event dynamically, we
|
||||
have a constant with a Hash of events:
|
||||
|
||||
```ruby
|
||||
INSTRUMENT = {
|
||||
serialize: :"serialize.serializer",
|
||||
associations: :"associations.serializer"
|
||||
}
|
||||
```
|
||||
|
||||
If Ruby ever fixes this issue and avoids generating garbage with dynamic
|
||||
symbols, this code can be removed.
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
require 'active_support/core_ext/class/attribute'
|
||||
|
||||
module ActionController
|
||||
# Action Controller Serialization
|
||||
#
|
||||
@ -32,27 +34,46 @@ module ActionController
|
||||
self._serialization_scope = :current_user
|
||||
end
|
||||
|
||||
def serialization_scope
|
||||
send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true)
|
||||
end
|
||||
|
||||
def default_serializer_options
|
||||
end
|
||||
|
||||
def _render_option_json(resource, options)
|
||||
json = ActiveModel::Serializer.build_json(self, resource, options)
|
||||
|
||||
if json
|
||||
super(json, options)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def serialization_scope(scope)
|
||||
self._serialization_scope = scope
|
||||
end
|
||||
end
|
||||
|
||||
def _render_option_json(resource, options)
|
||||
serializer = build_json_serializer(resource, options)
|
||||
|
||||
if serializer
|
||||
super(serializer, options)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_serializer_options
|
||||
{}
|
||||
end
|
||||
|
||||
def serialization_scope
|
||||
_serialization_scope = self.class._serialization_scope
|
||||
send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true)
|
||||
end
|
||||
|
||||
def build_json_serializer(resource, options)
|
||||
options = default_serializer_options.merge(options || {})
|
||||
|
||||
serializer =
|
||||
options.delete(:serializer) ||
|
||||
ActiveModel::Serializer.serializer_for(resource)
|
||||
|
||||
return unless serializer
|
||||
|
||||
options[:scope] = serialization_scope unless options.has_key?(:scope)
|
||||
options[:resource_name] = self.controller_name if resource.respond_to?(:to_ary)
|
||||
|
||||
serializer.new(resource, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,65 +1,35 @@
|
||||
require 'active_model/default_serializer'
|
||||
require 'active_model/serializable'
|
||||
require 'active_model/serializer/caching'
|
||||
require "active_support/core_ext/class/attribute"
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/descendants_tracker'
|
||||
require 'active_model/serializer'
|
||||
|
||||
module ActiveModel
|
||||
# Active Model Array Serializer
|
||||
#
|
||||
# Serializes an Array, checking if each element implements
|
||||
# the +active_model_serializer+ method.
|
||||
#
|
||||
# To disable serialization of root elements:
|
||||
#
|
||||
# ActiveModel::ArraySerializer.root = false
|
||||
#
|
||||
class ArraySerializer
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
|
||||
include ActiveModel::Serializable
|
||||
include ActiveModel::Serializer::Caching
|
||||
|
||||
attr_reader :object, :options
|
||||
|
||||
class_attribute :root
|
||||
|
||||
class_attribute :cache
|
||||
class_attribute :perform_caching
|
||||
include Serializable
|
||||
|
||||
class << self
|
||||
# set perform caching like root
|
||||
def cached(value = true)
|
||||
self.perform_caching = value
|
||||
end
|
||||
attr_accessor :_root
|
||||
alias root _root=
|
||||
alias root= _root=
|
||||
end
|
||||
|
||||
def initialize(object, options={})
|
||||
@object = object
|
||||
@options = options
|
||||
end
|
||||
|
||||
def serialize_object
|
||||
serializable_array
|
||||
@object = object
|
||||
@root = options[:root]
|
||||
@root = self.class._root if @root.nil?
|
||||
@root = options[:resource_name] if @root.nil?
|
||||
@meta_key = options[:meta_key] || :meta
|
||||
@meta = options[@meta_key]
|
||||
@each_serializer = options[:each_serializer]
|
||||
@options = options.merge(root: nil)
|
||||
end
|
||||
attr_accessor :object, :root, :meta_key, :meta
|
||||
|
||||
def serializable_array
|
||||
object.map do |item|
|
||||
if options.has_key? :each_serializer
|
||||
serializer = options[:each_serializer]
|
||||
elsif item.respond_to?(:active_model_serializer)
|
||||
serializer = item.active_model_serializer
|
||||
end
|
||||
serializer ||= DefaultSerializer
|
||||
|
||||
serializable = serializer.new(item, options.merge(root: nil))
|
||||
|
||||
if serializable.respond_to?(:serializable_hash)
|
||||
serializable.serializable_hash
|
||||
else
|
||||
serializable.as_json
|
||||
end
|
||||
@object.map do |item|
|
||||
serializer = @each_serializer || Serializer.serializer_for(item) || DefaultSerializer
|
||||
serializer.new(item, @options).serializable_object
|
||||
end
|
||||
end
|
||||
alias serializable_object serializable_array
|
||||
end
|
||||
end
|
||||
|
||||
17
lib/active_model/default_serializer.rb
Normal file
17
lib/active_model/default_serializer.rb
Normal file
@ -0,0 +1,17 @@
|
||||
module ActiveModel
|
||||
# DefaultSerializer
|
||||
#
|
||||
# Provides a constant interface for all items
|
||||
class DefaultSerializer
|
||||
attr_reader :object
|
||||
|
||||
def initialize(object, options=nil)
|
||||
@object = object
|
||||
end
|
||||
|
||||
def serializable_hash(*)
|
||||
@object.as_json
|
||||
end
|
||||
alias serializable_object serializable_hash
|
||||
end
|
||||
end
|
||||
@ -1,49 +1,21 @@
|
||||
require 'active_support/core_ext/object/to_json'
|
||||
|
||||
module ActiveModel
|
||||
# Enable classes to Classes including this module to serialize themselves by implementing a serialize method and an options method.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# require 'active_model_serializers'
|
||||
#
|
||||
# class MySerializer
|
||||
# include ActiveModel::Serializable
|
||||
#
|
||||
# def initialize
|
||||
# @options = {}
|
||||
# end
|
||||
#
|
||||
# attr_reader :options
|
||||
#
|
||||
# def serialize
|
||||
# { a: 1 }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# puts MySerializer.new.to_json
|
||||
module Serializable
|
||||
def as_json(args={})
|
||||
if root = args[:root] || options[:root]
|
||||
options[:hash] = hash = {}
|
||||
options[:unique_values] = {}
|
||||
|
||||
hash.merge!(root => serialize)
|
||||
include_meta hash
|
||||
def as_json(options={})
|
||||
if root = options[:root] || self.root
|
||||
hash = { root => serializable_object }
|
||||
hash.merge!(serializable_data)
|
||||
hash
|
||||
else
|
||||
serialize
|
||||
serializable_object
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def include_meta(hash)
|
||||
hash[meta_key] = options[:meta] if options.has_key?(:meta)
|
||||
end
|
||||
|
||||
def meta_key
|
||||
options[:meta_key].try(:to_sym) || :meta
|
||||
def serializable_data
|
||||
if respond_to?(:meta) && meta
|
||||
{ meta_key => meta }
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,124 +1,81 @@
|
||||
require 'active_model/array_serializer'
|
||||
require 'active_model/serializable'
|
||||
require 'active_model/serializer/caching'
|
||||
require "active_support/core_ext/class/attribute"
|
||||
require "active_support/core_ext/module/anonymous"
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/descendants_tracker'
|
||||
require 'active_model/serializer/associations'
|
||||
require 'active_model/serializer/settings'
|
||||
|
||||
module ActiveModel
|
||||
# Active Model Serializer
|
||||
#
|
||||
# Provides a basic serializer implementation that allows you to easily
|
||||
# control how a given object is going to be serialized. On initialization,
|
||||
# it expects two objects as arguments, a resource and options. For example,
|
||||
# one may do in a controller:
|
||||
#
|
||||
# PostSerializer.new(@post, scope: current_user).to_json
|
||||
#
|
||||
# The object to be serialized is the +@post+ and the current user is passed
|
||||
# in for authorization purposes.
|
||||
#
|
||||
# We use the scope to check if a given attribute should be serialized or not.
|
||||
# For example, some attributes may only be returned if +current_user+ is the
|
||||
# author of the post:
|
||||
#
|
||||
# class PostSerializer < ActiveModel::Serializer
|
||||
# attributes :title, :body
|
||||
# has_many :comments
|
||||
#
|
||||
# private
|
||||
#
|
||||
# def attributes
|
||||
# hash = super
|
||||
# hash.merge!(email: post.email) if author?
|
||||
# hash
|
||||
# end
|
||||
#
|
||||
# def author?
|
||||
# post.author == scope
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class Serializer
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
|
||||
include ActiveModel::Serializable
|
||||
include ActiveModel::Serializer::Caching
|
||||
|
||||
INCLUDE_METHODS = {}
|
||||
INSTRUMENT = { serialize: :"serialize.serializer", associations: :"associations.serializer" }
|
||||
|
||||
class IncludeError < StandardError
|
||||
attr_reader :source, :association
|
||||
|
||||
def initialize(source, association)
|
||||
@source, @association = source, association
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Cannot serialize #{association} when #{source} does not have a root!"
|
||||
end
|
||||
end
|
||||
|
||||
class_attribute :_attributes
|
||||
self._attributes = {}
|
||||
|
||||
class_attribute :_associations
|
||||
self._associations = {}
|
||||
|
||||
class_attribute :_root
|
||||
class_attribute :_embed
|
||||
self._embed = :objects
|
||||
class_attribute :_root_embed
|
||||
|
||||
class_attribute :cache
|
||||
class_attribute :perform_caching
|
||||
include Serializable
|
||||
|
||||
class << self
|
||||
def cached(value = true)
|
||||
self.perform_caching = value
|
||||
def inherited(base)
|
||||
base._attributes = []
|
||||
base._associations = {}
|
||||
end
|
||||
|
||||
# Define attributes to be used in the serialization.
|
||||
def attributes(*attrs)
|
||||
def setup
|
||||
yield SETTINGS
|
||||
end
|
||||
|
||||
self._attributes = _attributes.dup
|
||||
def embed(type, options={})
|
||||
SETTINGS[:embed] = type
|
||||
SETTINGS[:include] = true if options[:include]
|
||||
end
|
||||
|
||||
if RUBY_VERSION >= '2.0'
|
||||
def serializer_for(resource)
|
||||
if resource.respond_to?(:to_ary)
|
||||
ArraySerializer
|
||||
else
|
||||
begin
|
||||
Object.const_get "#{resource.class.name}Serializer"
|
||||
rescue NameError
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
def serializer_for(resource)
|
||||
if resource.respond_to?(:to_ary)
|
||||
ArraySerializer
|
||||
else
|
||||
"#{resource.class.name}Serializer".safe_constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :_root, :_attributes, :_associations
|
||||
alias root _root=
|
||||
alias root= _root=
|
||||
|
||||
def root_name
|
||||
name.demodulize.underscore.sub(/_serializer$/, '') if name
|
||||
end
|
||||
|
||||
def attributes(*attrs)
|
||||
@_attributes.concat attrs
|
||||
|
||||
attrs.each do |attr|
|
||||
if Hash === attr
|
||||
attr.each {|attr_real, key| attribute(attr_real, key: key) }
|
||||
else
|
||||
attribute attr
|
||||
unless method_defined?(attr)
|
||||
define_method attr do
|
||||
object.read_attribute_for_serialization(attr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def attribute(attr, options={})
|
||||
self._attributes = _attributes.merge(attr.is_a?(Hash) ? attr : {attr => options[:key] || attr.to_s.gsub(/\?$/, '').to_sym})
|
||||
|
||||
attr = attr.keys[0] if attr.is_a? Hash
|
||||
|
||||
unless method_defined?(attr)
|
||||
define_method attr do
|
||||
object.read_attribute_for_serialization(attr.to_sym)
|
||||
end
|
||||
end
|
||||
|
||||
define_include_method attr
|
||||
|
||||
# protect inheritance chains and open classes
|
||||
# if a serializer inherits from another OR
|
||||
# attributes are added later in a classes lifecycle
|
||||
# poison the cache
|
||||
define_method :_fast_attributes do
|
||||
raise NameError
|
||||
end
|
||||
|
||||
def has_one(*attrs)
|
||||
associate(Association::HasOne, *attrs)
|
||||
end
|
||||
|
||||
def associate(klass, attrs) #:nodoc:
|
||||
def has_many(*attrs)
|
||||
associate(Association::HasMany, *attrs)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def associate(klass, *attrs)
|
||||
options = attrs.extract_options!
|
||||
self._associations = _associations.dup
|
||||
|
||||
attrs.each do |attr|
|
||||
unless method_defined?(attr)
|
||||
@ -127,349 +84,91 @@ module ActiveModel
|
||||
end
|
||||
end
|
||||
|
||||
define_include_method attr
|
||||
|
||||
self._associations[attr] = [klass, options]
|
||||
@_associations[attr] = klass.new(attr, options)
|
||||
end
|
||||
end
|
||||
|
||||
def define_include_method(name)
|
||||
method = "include_#{name}?".to_sym
|
||||
|
||||
INCLUDE_METHODS[name] = method
|
||||
|
||||
unless method_defined?(method)
|
||||
define_method method do
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an array when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def has_many(*attrs)
|
||||
associate(Association::HasMany, attrs)
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an object when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def has_one(*attrs)
|
||||
associate(Association::HasOne, attrs)
|
||||
end
|
||||
|
||||
# Return a schema hash for the current serializer. This information
|
||||
# can be used to generate clients for the serialized output.
|
||||
#
|
||||
# The schema hash has two keys: +attributes+ and +associations+.
|
||||
#
|
||||
# The +attributes+ hash looks like this:
|
||||
#
|
||||
# { name: :string, age: :integer }
|
||||
#
|
||||
# The +associations+ hash looks like this:
|
||||
# { posts: { has_many: :posts } }
|
||||
#
|
||||
# If :key is used:
|
||||
#
|
||||
# class PostsSerializer < ActiveModel::Serializer
|
||||
# has_many :posts, key: :my_posts
|
||||
# end
|
||||
#
|
||||
# the hash looks like this:
|
||||
#
|
||||
# { my_posts: { has_many: :posts }
|
||||
#
|
||||
# This information is extracted from the serializer's model class,
|
||||
# which is provided by +SerializerClass.model_class+.
|
||||
#
|
||||
# The schema method uses the +columns_hash+ and +reflect_on_association+
|
||||
# methods, provided by default by ActiveRecord. You can implement these
|
||||
# methods on your custom models if you want the serializer's schema method
|
||||
# to work.
|
||||
#
|
||||
# TODO: This is currently coupled to Active Record. We need to
|
||||
# figure out a way to decouple those two.
|
||||
def schema
|
||||
klass = model_class
|
||||
columns = klass.columns_hash
|
||||
|
||||
attrs = {}
|
||||
_attributes.each do |name, key|
|
||||
if column = columns[name.to_s]
|
||||
attrs[key] = column.type
|
||||
else
|
||||
# Computed attribute (method on serializer or model). We cannot
|
||||
# infer the type, so we put nil, unless specified in the attribute declaration
|
||||
if name != key
|
||||
attrs[name] = key
|
||||
else
|
||||
attrs[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
associations = {}
|
||||
_associations.each do |attr, (association_class, options)|
|
||||
association = association_class.new(attr, options)
|
||||
|
||||
if model_association = klass.reflect_on_association(association.name)
|
||||
# Real association.
|
||||
associations[association.key] = { model_association.macro => model_association.name }
|
||||
else
|
||||
# Computed association. We could infer has_many vs. has_one from
|
||||
# the association class, but that would make it different from
|
||||
# real associations, which read has_one vs. belongs_to from the
|
||||
# model.
|
||||
associations[association.key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
{ attributes: attrs, associations: associations }
|
||||
end
|
||||
|
||||
# The model class associated with this serializer.
|
||||
def model_class
|
||||
name.sub(/Serializer$/, '').constantize
|
||||
end
|
||||
|
||||
# Define how associations should be embedded.
|
||||
#
|
||||
# embed :objects # Embed associations as full objects
|
||||
# embed :ids # Embed only the association ids
|
||||
# embed :ids, include: true # Embed the association ids and include objects in the root
|
||||
#
|
||||
def embed(type, options={})
|
||||
self._embed = type
|
||||
self._root_embed = true if options[:include]
|
||||
end
|
||||
|
||||
# Defines the root used on serialization. If false, disables the root.
|
||||
def root(name)
|
||||
self._root = name
|
||||
end
|
||||
alias_method :root=, :root
|
||||
|
||||
# Used internally to create a new serializer object based on controller
|
||||
# settings and options for a given resource. These settings are typically
|
||||
# set during the request lifecycle or by the controller class, and should
|
||||
# not be manually defined for this method.
|
||||
def build_json(controller, resource, options)
|
||||
default_options = controller.send(:default_serializer_options) || {}
|
||||
options = default_options.merge(options || {})
|
||||
|
||||
serializer = options.delete(:serializer) ||
|
||||
(resource.respond_to?(:active_model_serializer) &&
|
||||
resource.active_model_serializer)
|
||||
|
||||
return serializer unless serializer
|
||||
|
||||
if resource.respond_to?(:to_ary)
|
||||
unless serializer <= ActiveModel::ArraySerializer
|
||||
raise ArgumentError.new("#{serializer.name} is not an ArraySerializer. " +
|
||||
"You may want to use the :each_serializer option instead.")
|
||||
end
|
||||
|
||||
if options[:root] != false && serializer.root != false
|
||||
# the serializer for an Array is ActiveModel::ArraySerializer
|
||||
options[:root] ||= serializer.root || controller.controller_name
|
||||
end
|
||||
end
|
||||
|
||||
options[:scope] = controller.serialization_scope unless options.has_key?(:scope)
|
||||
options[:scope_name] = controller._serialization_scope unless options.has_key?(:scope_name)
|
||||
options[:url_options] = controller.url_options
|
||||
|
||||
serializer.new(resource, options)
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :object, :options
|
||||
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
@object = object
|
||||
@scope = options[:scope]
|
||||
self.root = options[:root]
|
||||
@meta_key = options[:meta_key] || :meta
|
||||
@meta = options[@meta_key]
|
||||
end
|
||||
attr_accessor :object, :scope, :meta_key, :meta
|
||||
attr_reader :root
|
||||
|
||||
scope_name = @options[:scope_name]
|
||||
if scope_name && !respond_to?(scope_name)
|
||||
self.class.class_eval do
|
||||
define_method scope_name, lambda { scope }
|
||||
end
|
||||
end
|
||||
def root=(root)
|
||||
@root = root
|
||||
@root = self.class._root if @root.nil?
|
||||
@root = self.class.root_name if @root == true || @root.nil?
|
||||
end
|
||||
|
||||
def root_name
|
||||
return false if self._root == false
|
||||
|
||||
class_name = self.class.name.demodulize.underscore.sub(/_serializer$/, '').to_sym unless self.class.name.blank?
|
||||
|
||||
if self._root == true
|
||||
class_name
|
||||
else
|
||||
self._root || class_name
|
||||
end
|
||||
end
|
||||
|
||||
def url_options
|
||||
@options[:url_options] || {}
|
||||
end
|
||||
|
||||
# Returns a json representation of the serializable
|
||||
# object including the root.
|
||||
def as_json(args={})
|
||||
super(root: args.fetch(:root, options.fetch(:root, root_name)))
|
||||
end
|
||||
|
||||
def serialize_object
|
||||
serializable_hash
|
||||
end
|
||||
|
||||
# Returns a hash representation of the serializable
|
||||
# object without the root.
|
||||
def serializable_hash
|
||||
return nil if @object.nil?
|
||||
@node = attributes
|
||||
include_associations! if _embed
|
||||
@node
|
||||
end
|
||||
|
||||
def include_associations!
|
||||
_associations.each_key do |name|
|
||||
include!(name) if include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
def include?(name)
|
||||
return false if @options.key?(:only) && !Array(@options[:only]).include?(name)
|
||||
return false if @options.key?(:except) && Array(@options[:except]).include?(name)
|
||||
send INCLUDE_METHODS[name]
|
||||
end
|
||||
|
||||
def include!(name, options={})
|
||||
hash = @options[:hash]
|
||||
unique_values = @options[:unique_values] ||= {}
|
||||
|
||||
node = options[:node] ||= @node
|
||||
value = options[:value]
|
||||
|
||||
if options[:include] == nil
|
||||
if @options.key?(:include)
|
||||
options[:include] = @options[:include].include?(name)
|
||||
elsif @options.include?(:exclude)
|
||||
options[:include] = !@options[:exclude].include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
klass, klass_options = _associations[name]
|
||||
association_class =
|
||||
if klass
|
||||
options = klass_options.merge options
|
||||
klass
|
||||
elsif value.respond_to?(:to_ary)
|
||||
Association::HasMany
|
||||
else
|
||||
Association::HasOne
|
||||
end
|
||||
|
||||
options = default_embed_options.merge!(options)
|
||||
options[:value] ||= send(name)
|
||||
association = association_class.new(name, options, self.options)
|
||||
|
||||
if association.embed_ids?
|
||||
node[association.key] = association.serialize_ids
|
||||
|
||||
if association.embed_in_root? && hash.nil?
|
||||
raise IncludeError.new(self.class, association.name)
|
||||
elsif association.embed_in_root? && association.embeddable?
|
||||
merge_association hash, association.root, association.serializables, unique_values
|
||||
end
|
||||
elsif association.embed_objects?
|
||||
node[association.key] = association.serialize
|
||||
end
|
||||
end
|
||||
|
||||
# In some cases, an Array of associations is built by merging the associated
|
||||
# content for all of the children. For instance, if a Post has_many comments,
|
||||
# which has_many tags, the top-level :tags key will contain the merged list
|
||||
# of all tags for all comments of the post.
|
||||
#
|
||||
# In order to make this efficient, we store a :unique_values hash containing
|
||||
# a unique list of all of the objects that are already in the Array. This
|
||||
# avoids the need to scan through the Array looking for entries every time
|
||||
# we want to merge a new list of values.
|
||||
def merge_association(hash, key, serializables, unique_values)
|
||||
already_serialized = (unique_values[key] ||= {})
|
||||
serializable_hashes = (hash[key] ||= [])
|
||||
|
||||
serializables.each do |serializable|
|
||||
unless already_serialized.include? serializable.object
|
||||
already_serialized[serializable.object] = true
|
||||
serializable_hashes << serializable.serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a hash representation of the serializable
|
||||
# object attributes.
|
||||
def attributes
|
||||
_fast_attributes
|
||||
rescue NameError
|
||||
method = "def _fast_attributes\n"
|
||||
filter(self.class._attributes.dup).each_with_object({}) do |name, hash|
|
||||
hash[name] = send(name)
|
||||
end
|
||||
end
|
||||
|
||||
method << " h = {}\n"
|
||||
|
||||
_attributes.each do |name,key|
|
||||
method << " h[:\"#{key}\"] = read_attribute_for_serialization(:\"#{name}\") if include?(:\"#{name}\")\n"
|
||||
def associations
|
||||
associations = self.class._associations
|
||||
included_associations = filter(associations.keys)
|
||||
associations.each_with_object({}) do |(name, association), hash|
|
||||
if included_associations.include? name
|
||||
if association.embed_ids?
|
||||
hash[association.key] = serialize_ids association
|
||||
elsif association.embed_objects?
|
||||
hash[association.embedded_key] = serialize association
|
||||
end
|
||||
end
|
||||
method << " h\nend"
|
||||
|
||||
self.class.class_eval method
|
||||
_fast_attributes
|
||||
end
|
||||
end
|
||||
|
||||
# Returns options[:scope]
|
||||
def scope
|
||||
@options[:scope]
|
||||
def filter(keys)
|
||||
keys
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
|
||||
# Use ActiveSupport::Notifications to send events to external systems.
|
||||
# The event name is: name.class_name.serializer
|
||||
def instrument(name, payload = {}, &block)
|
||||
event_name = INSTRUMENT[name]
|
||||
ActiveSupport::Notifications.instrument(event_name, payload, &block)
|
||||
def serializable_data
|
||||
embedded_in_root_associations.merge!(super)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_embed_options
|
||||
{
|
||||
embed: _embed,
|
||||
include: _root_embed
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# DefaultSerializer
|
||||
#
|
||||
# Provides a constant interface for all items, particularly
|
||||
# for ArraySerializer.
|
||||
class DefaultSerializer
|
||||
attr_reader :object, :options
|
||||
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
def embedded_in_root_associations
|
||||
associations = self.class._associations
|
||||
included_associations = filter(associations.keys)
|
||||
associations.each_with_object({}) do |(name, association), hash|
|
||||
if included_associations.include? name
|
||||
if association.embed_in_root?
|
||||
hash[association.embedded_key] = serialize association
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def serializable_hash
|
||||
@object.as_json(@options)
|
||||
def serialize(association)
|
||||
associated_data = send(association.name)
|
||||
if associated_data.respond_to?(:to_ary)
|
||||
associated_data.map { |elem| association.build_serializer(elem).serializable_hash }
|
||||
else
|
||||
result = association.build_serializer(associated_data).serializable_hash
|
||||
association.is_a?(Association::HasMany) ? [result] : result
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_ids(association)
|
||||
associated_data = send(association.name)
|
||||
if associated_data.respond_to?(:to_ary)
|
||||
associated_data.map { |elem| elem.read_attribute_for_serialization(association.embed_key) }
|
||||
else
|
||||
associated_data.read_attribute_for_serialization(association.embed_key) if associated_data
|
||||
end
|
||||
end
|
||||
|
||||
def serializable_hash(options={})
|
||||
return nil if object.nil?
|
||||
hash = attributes
|
||||
hash.merge! associations
|
||||
end
|
||||
alias serializable_object serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,183 +1,53 @@
|
||||
require 'active_model/default_serializer'
|
||||
require 'active_model/serializer'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Association #:nodoc:
|
||||
# name: The name of the association.
|
||||
#
|
||||
# options: A hash. These keys are accepted:
|
||||
#
|
||||
# value: The object we're associating with.
|
||||
#
|
||||
# serializer: The class used to serialize the association.
|
||||
#
|
||||
# embed: Define how associations should be embedded.
|
||||
# - :objects # Embed associations as full objects.
|
||||
# - :ids # Embed only the association ids.
|
||||
# - :ids, include: true # Embed the association ids and include objects in the root.
|
||||
#
|
||||
# include: Used in conjunction with embed :ids. Includes the objects in the root.
|
||||
#
|
||||
# root: Used in conjunction with include: true. Defines the key used to embed the objects.
|
||||
#
|
||||
# key: Key name used to store the ids in.
|
||||
#
|
||||
# embed_key: Method used to fetch ids. Defaults to :id.
|
||||
#
|
||||
# polymorphic: Is the association is polymorphic?. Values: true or false.
|
||||
def initialize(name, options={}, serializer_options={})
|
||||
@name = name
|
||||
@object = options[:value]
|
||||
class Association
|
||||
def initialize(name, options={})
|
||||
@name = name.to_s
|
||||
@options = options
|
||||
|
||||
embed = options[:embed]
|
||||
@embed_ids = embed == :id || embed == :ids
|
||||
@embed_objects = embed == :object || embed == :objects
|
||||
self.embed = options[:embed] || SETTINGS[:embed] || :objects
|
||||
@embed_in_root = @embed_ids && (options[:include] || SETTINGS[:include])
|
||||
@embed_key = options[:embed_key] || :id
|
||||
@embed_in_root = options[:include]
|
||||
@key = options[:key]
|
||||
@embedded_key = options[:root] || name
|
||||
|
||||
serializer = options[:serializer]
|
||||
@serializer_class = serializer.is_a?(String) ? serializer.constantize : serializer
|
||||
|
||||
@options = options
|
||||
@serializer_options = serializer_options
|
||||
self.serializer_class = @options[:serializer]
|
||||
end
|
||||
|
||||
attr_reader :object, :root, :name, :embed_ids, :embed_objects, :embed_in_root
|
||||
alias embeddable? object
|
||||
alias embed_objects? embed_objects
|
||||
attr_reader :name, :embed_ids, :embed_objects, :serializer_class
|
||||
attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :options
|
||||
alias embed_ids? embed_ids
|
||||
alias use_id_key? embed_ids?
|
||||
alias embed_objects? embed_objects
|
||||
alias embed_in_root? embed_in_root
|
||||
|
||||
def key
|
||||
if key = options[:key]
|
||||
key
|
||||
elsif use_id_key?
|
||||
id_key
|
||||
else
|
||||
name
|
||||
end
|
||||
def serializer_class=(serializer)
|
||||
@serializer_class = serializer.is_a?(String) ? serializer.constantize : serializer
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :embed_key, :serializer_class, :options, :serializer_options
|
||||
|
||||
def find_serializable(object)
|
||||
if serializer_class
|
||||
serializer_class.new(object, serializer_options)
|
||||
elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer)
|
||||
ams.new(object, serializer_options)
|
||||
else
|
||||
object
|
||||
end
|
||||
def embed=(embed)
|
||||
@embed_ids = embed == :id || embed == :ids
|
||||
@embed_objects = embed == :object || embed == :objects
|
||||
end
|
||||
|
||||
class HasMany < Association #:nodoc:
|
||||
def root
|
||||
options[:root] || name
|
||||
end
|
||||
|
||||
def id_key
|
||||
"#{name.to_s.singularize}_ids".to_sym
|
||||
end
|
||||
|
||||
def serializables
|
||||
object.map do |item|
|
||||
find_serializable(item)
|
||||
end
|
||||
end
|
||||
|
||||
def serialize
|
||||
object.map do |item|
|
||||
find_serializable(item).serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_ids
|
||||
object.map do |item|
|
||||
serializer = find_serializable(item)
|
||||
if serializer.respond_to?(embed_key)
|
||||
serializer.send(embed_key)
|
||||
else
|
||||
item.read_attribute_for_serialization(embed_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
def build_serializer(object)
|
||||
@serializer_class ||= Serializer.serializer_for(object) || DefaultSerializer
|
||||
@serializer_class.new(object, @options)
|
||||
end
|
||||
|
||||
class HasOne < Association #:nodoc:
|
||||
def initialize(name, options={}, serializer_options={})
|
||||
class HasOne < Association
|
||||
def initialize(*args)
|
||||
super
|
||||
@polymorphic = options[:polymorphic]
|
||||
@key ||= "#{name}_id"
|
||||
end
|
||||
end
|
||||
|
||||
def root
|
||||
if root = options[:root]
|
||||
root
|
||||
elsif polymorphic?
|
||||
object.class.to_s.pluralize.demodulize.underscore.to_sym
|
||||
else
|
||||
name.to_s.pluralize.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
def id_key
|
||||
"#{name}_id".to_sym
|
||||
end
|
||||
|
||||
def embeddable?
|
||||
super || !polymorphic?
|
||||
end
|
||||
|
||||
def serializables
|
||||
value = object && find_serializable(object)
|
||||
value ? [value] : []
|
||||
end
|
||||
|
||||
def serialize
|
||||
if object
|
||||
if polymorphic?
|
||||
{
|
||||
:type => polymorphic_key,
|
||||
polymorphic_key => find_serializable(object).serializable_hash
|
||||
}
|
||||
else
|
||||
find_serializable(object).serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_ids
|
||||
if object
|
||||
serializer = find_serializable(object)
|
||||
id =
|
||||
if serializer.respond_to?(embed_key)
|
||||
serializer.send(embed_key)
|
||||
else
|
||||
object.read_attribute_for_serialization(embed_key)
|
||||
end
|
||||
|
||||
if polymorphic?
|
||||
{
|
||||
type: polymorphic_key,
|
||||
id: id
|
||||
}
|
||||
else
|
||||
id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :polymorphic
|
||||
alias polymorphic? polymorphic
|
||||
|
||||
def use_id_key?
|
||||
embed_ids? && !polymorphic?
|
||||
end
|
||||
|
||||
def polymorphic_key
|
||||
object.class.to_s.demodulize.underscore.to_sym
|
||||
class HasMany < Association
|
||||
def initialize(*args)
|
||||
super
|
||||
@key ||= "#{name.singularize}_ids"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Caching
|
||||
def to_json(*args)
|
||||
if caching_enabled?
|
||||
key = expand_cache_key([self.class.to_s.underscore, cache_key, 'to-json'])
|
||||
cache.fetch key do
|
||||
super
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def serialize(*args)
|
||||
if caching_enabled?
|
||||
key = expand_cache_key([self.class.to_s.underscore, cache_key, 'serialize'])
|
||||
cache.fetch key do
|
||||
serialize_object
|
||||
end
|
||||
else
|
||||
serialize_object
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def caching_enabled?
|
||||
perform_caching && cache && respond_to?(:cache_key)
|
||||
end
|
||||
|
||||
def expand_cache_key(*args)
|
||||
ActiveSupport::Cache.expand_cache_key(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
13
lib/active_model/serializer/generators/resource_override.rb
Normal file
13
lib/active_model/serializer/generators/resource_override.rb
Normal file
@ -0,0 +1,13 @@
|
||||
require 'rails/generators'
|
||||
require 'rails/generators/rails/resource/resource_generator'
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
class ResourceGenerator
|
||||
def add_serializer
|
||||
invoke 'serializer'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
module Rails
|
||||
module Generators
|
||||
class SerializerGenerator < NamedBase
|
||||
source_root File.expand_path("../templates", __FILE__)
|
||||
check_class_collision suffix: "Serializer"
|
||||
source_root File.expand_path('../templates', __FILE__)
|
||||
check_class_collision suffix: 'Serializer'
|
||||
|
||||
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
||||
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
||||
|
||||
class_option :parent, type: :string, desc: "The parent class for the generated serializer"
|
||||
class_option :parent, type: :string, desc: 'The parent class for the generated serializer'
|
||||
|
||||
def create_serializer_file
|
||||
template 'serializer.rb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
|
||||
@ -25,10 +25,11 @@ module Rails
|
||||
def parent_class_name
|
||||
if options[:parent]
|
||||
options[:parent]
|
||||
elsif defined?(::ApplicationSerializer)
|
||||
"ApplicationSerializer"
|
||||
elsif (ns = Rails::Generators.namespace) && ns.const_defined?(:ApplicationSerializer) ||
|
||||
defined?(::ApplicationSerializer)
|
||||
'ApplicationSerializer'
|
||||
else
|
||||
"ActiveModel::Serializer"
|
||||
'ActiveModel::Serializer'
|
||||
end
|
||||
end
|
||||
end
|
||||
10
lib/active_model/serializer/railtie.rb
Normal file
10
lib/active_model/serializer/railtie.rb
Normal file
@ -0,0 +1,10 @@
|
||||
module ActiveModel
|
||||
class Railtie < Rails::Railtie
|
||||
initializer 'generators' do |app|
|
||||
require 'rails/generators'
|
||||
require 'active_model/serializer/generators/serializer/serializer_generator'
|
||||
Rails::Generators.configure!(app.config.generators)
|
||||
require 'active_model/serializer/generators/resource_override'
|
||||
end
|
||||
end
|
||||
end
|
||||
27
lib/active_model/serializer/settings.rb
Normal file
27
lib/active_model/serializer/settings.rb
Normal file
@ -0,0 +1,27 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Settings
|
||||
def initialize
|
||||
@data = {}
|
||||
end
|
||||
|
||||
def [](key)
|
||||
@data[key.to_s]
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
@data[key.to_s] = value
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
@data.each(&block)
|
||||
end
|
||||
|
||||
def clear
|
||||
@data.clear
|
||||
end
|
||||
end
|
||||
|
||||
SETTINGS = Settings.new
|
||||
end
|
||||
end
|
||||
@ -1,5 +1,5 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
VERSION = "0.8.1"
|
||||
VERSION = "0.9.0.pre"
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,85 +1,7 @@
|
||||
require "active_support"
|
||||
require "active_support/core_ext/string/inflections"
|
||||
require "active_support/notifications"
|
||||
require "active_model"
|
||||
require "active_model/array_serializer"
|
||||
require "active_model/serializer"
|
||||
require "active_model/serializer/associations"
|
||||
require "set"
|
||||
|
||||
if defined?(Rails)
|
||||
module ActiveModel
|
||||
class Railtie < Rails::Railtie
|
||||
generators do |app|
|
||||
Rails::Generators.configure!(app.config.generators)
|
||||
Rails::Generators.hidden_namespaces.uniq!
|
||||
require_relative "generators/resource_override"
|
||||
end
|
||||
|
||||
initializer "include_routes.active_model_serializer" do |app|
|
||||
ActiveSupport.on_load(:active_model_serializers) do
|
||||
include AbstractController::UrlFor
|
||||
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
|
||||
include app.routes.mounted_helpers
|
||||
end
|
||||
end
|
||||
|
||||
initializer "caching.active_model_serializer" do |app|
|
||||
ActiveModel::Serializer.perform_caching = app.config.action_controller.perform_caching
|
||||
ActiveModel::ArraySerializer.perform_caching = app.config.action_controller.perform_caching
|
||||
|
||||
ActiveModel::Serializer.cache = Rails.cache
|
||||
ActiveModel::ArraySerializer.cache = Rails.cache
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveModel::SerializerSupport
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods #:nodoc:
|
||||
if "".respond_to?(:safe_constantize)
|
||||
def active_model_serializer
|
||||
"#{self.name}Serializer".safe_constantize
|
||||
end
|
||||
else
|
||||
def active_model_serializer
|
||||
begin
|
||||
"#{self.name}Serializer".constantize
|
||||
rescue NameError => e
|
||||
raise unless e.message =~ /uninitialized constant/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a model serializer for this object considering its namespace.
|
||||
def active_model_serializer
|
||||
self.class.active_model_serializer
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
end
|
||||
|
||||
module ActiveModel::ArraySerializerSupport
|
||||
def active_model_serializer
|
||||
ActiveModel::ArraySerializer
|
||||
end
|
||||
end
|
||||
|
||||
Array.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
Set.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
|
||||
{
|
||||
active_record: 'ActiveRecord::Relation',
|
||||
mongoid: 'Mongoid::Criteria'
|
||||
}.each do |orm, rel_class|
|
||||
ActiveSupport.on_load(orm) do
|
||||
include ActiveModel::SerializerSupport
|
||||
rel_class.constantize.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
end
|
||||
end
|
||||
require 'active_model'
|
||||
require 'active_model/serializer'
|
||||
require 'active_model/serializer/version'
|
||||
require 'active_model/serializer/railtie' if defined?(Rails)
|
||||
|
||||
begin
|
||||
require 'action_controller'
|
||||
@ -88,8 +10,6 @@ begin
|
||||
ActiveSupport.on_load(:action_controller) do
|
||||
include ::ActionController::Serialization
|
||||
end
|
||||
rescue LoadError => ex
|
||||
# rails on installed, continuing
|
||||
rescue LoadError
|
||||
# rails not installed, continuing
|
||||
end
|
||||
|
||||
ActiveSupport.run_load_hooks(:active_model_serializers, ActiveModel::Serializer)
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
# We do not recommend that you use AM::S in this way, but if you must, here
|
||||
# is a mixin that overrides ActiveRecord::Base#to_json and #as_json.
|
||||
|
||||
module ActiveRecord
|
||||
module SerializerOverride
|
||||
def to_json options = {}
|
||||
active_model_serializer.new(self).to_json options
|
||||
end
|
||||
|
||||
def as_json options={}
|
||||
active_model_serializer.new(self).as_json options
|
||||
end
|
||||
end
|
||||
|
||||
Base.send(:include, SerializerOverride)
|
||||
end
|
||||
@ -1,13 +0,0 @@
|
||||
require "rails/generators"
|
||||
require "rails/generators/rails/resource/resource_generator"
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
ResourceGenerator.class_eval do
|
||||
def add_serializer
|
||||
invoke "serializer"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
require "test_helper"
|
||||
require "test_fakes"
|
||||
|
||||
class ArraySerializerTest < ActiveModel::TestCase
|
||||
# serialize different typed objects
|
||||
def test_array_serializer
|
||||
model = Model.new
|
||||
user = User.new
|
||||
comments = Comment.new(title: "Comment1", id: 1)
|
||||
|
||||
array = [model, user, comments]
|
||||
serializer = array.active_model_serializer.new(array, scope: { scope: true })
|
||||
assert_equal([
|
||||
{ model: "Model" },
|
||||
{ last_name: "Valim", ok: true, first_name: "Jose", scope: true },
|
||||
{ title: "Comment1" }
|
||||
], serializer.as_json)
|
||||
end
|
||||
|
||||
def test_array_serializer_with_root
|
||||
comment1 = Comment.new(title: "Comment1", id: 1)
|
||||
comment2 = Comment.new(title: "Comment2", id: 2)
|
||||
|
||||
array = [ comment1, comment2 ]
|
||||
|
||||
serializer = array.active_model_serializer.new(array, root: :comments)
|
||||
|
||||
assert_equal({ comments: [
|
||||
{ title: "Comment1" },
|
||||
{ title: "Comment2" }
|
||||
]}, serializer.as_json)
|
||||
end
|
||||
|
||||
def test_active_model_with_root
|
||||
comment1 = ModelWithActiveModelSerializer.new(title: "Comment1")
|
||||
comment2 = ModelWithActiveModelSerializer.new(title: "Comment2")
|
||||
|
||||
array = [ comment1, comment2 ]
|
||||
|
||||
serializer = array.active_model_serializer.new(array, root: :comments)
|
||||
|
||||
assert_equal({ comments: [
|
||||
{ title: "Comment1" },
|
||||
{ title: "Comment2" }
|
||||
]}, serializer.as_json)
|
||||
end
|
||||
|
||||
def test_array_serializer_with_hash
|
||||
hash = { value: "something" }
|
||||
array = [hash]
|
||||
serializer = array.active_model_serializer.new(array, root: :items)
|
||||
assert_equal({ items: [hash.as_json] }, serializer.as_json)
|
||||
end
|
||||
|
||||
def test_array_serializer_with_specified_serializer
|
||||
post1 = Post.new(title: "Post1", author: "Author1", id: 1)
|
||||
post2 = Post.new(title: "Post2", author: "Author2", id: 2)
|
||||
|
||||
array = [ post1, post2 ]
|
||||
|
||||
serializer = array.active_model_serializer.new array, each_serializer: CustomPostSerializer
|
||||
|
||||
assert_equal([
|
||||
{ title: "Post1" },
|
||||
{ title: "Post2" }
|
||||
], serializer.as_json)
|
||||
end
|
||||
|
||||
def test_array_serializer_using_default_serializer
|
||||
hash = { "value" => "something" }
|
||||
class << hash
|
||||
def active_model_serializer
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
array = [hash]
|
||||
|
||||
serializer = array.active_model_serializer.new array
|
||||
|
||||
assert_equal([
|
||||
{ "value" => "something" }
|
||||
], serializer.as_json)
|
||||
end
|
||||
end
|
||||
@ -1,592 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class AssociationTest < ActiveModel::TestCase
|
||||
def def_serializer(&block)
|
||||
Class.new(ActiveModel::Serializer, &block)
|
||||
end
|
||||
|
||||
class Model
|
||||
def initialize(hash={})
|
||||
@attributes = hash
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
@attributes[name]
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ model: "Model" }
|
||||
end
|
||||
|
||||
def method_missing(meth, *args)
|
||||
if meth.to_s =~ /^(.*)=$/
|
||||
@attributes[$1.to_sym] = args[0]
|
||||
elsif @attributes.key?(meth)
|
||||
@attributes[meth]
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@hash = {}
|
||||
@root_hash = {}
|
||||
|
||||
@post = Model.new(title: "New Post", body: "Body")
|
||||
@comment = Model.new(id: 1, external_id: "COMM001", body: "ZOMG A COMMENT")
|
||||
@post.comments = [ @comment ]
|
||||
@post.comment = @comment
|
||||
|
||||
@comment_serializer_class = def_serializer do
|
||||
attributes :id, :external_id, :body
|
||||
end
|
||||
|
||||
@post_serializer_class = def_serializer do
|
||||
attributes :title, :body
|
||||
end
|
||||
|
||||
@post_serializer = @post_serializer_class.new(@post, hash: @root_hash)
|
||||
end
|
||||
|
||||
def include!(key, options={})
|
||||
@post_serializer.include! key, {
|
||||
embed: :ids,
|
||||
include: true,
|
||||
node: @hash,
|
||||
serializer: @comment_serializer_class
|
||||
}.merge(options)
|
||||
end
|
||||
|
||||
def include_bare!(key, options={})
|
||||
@post_serializer.include! key, {
|
||||
node: @hash,
|
||||
serializer: @comment_serializer_class
|
||||
}.merge(options)
|
||||
end
|
||||
|
||||
class NoDefaults < AssociationTest
|
||||
def test_include_bang_has_many_associations
|
||||
include! :comments, value: @post.comments
|
||||
|
||||
assert_equal({
|
||||
comment_ids: [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_include_bang_with_embed_false
|
||||
include! :comments, value: @post.comments, embed: false
|
||||
|
||||
assert_equal({}, @hash)
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_include_bang_with_embed_ids_include_false
|
||||
include! :comments, value: @post.comments, embed: :ids, include: false
|
||||
|
||||
assert_equal({
|
||||
comment_ids: [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_include_bang_has_one_associations
|
||||
include! :comment, value: @post.comment
|
||||
|
||||
assert_equal({
|
||||
comment_id: 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }]
|
||||
}, @root_hash)
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultsTest < AssociationTest
|
||||
def test_with_default_has_many
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
comment_ids: [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
comment_id: 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_many_with_custom_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, key: :custom_comments
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
custom_comments: [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one_with_custom_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, key: :custom_comment_id
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
custom_comment_id: 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_many_with_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, embed_key: :external_id
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
comment_ids: [ "COMM001" ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one_with_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, embed_key: :external_id
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
comment_id: "COMM001"
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_many_with_custom_key_and_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, key: :custom_comments, embed_key: :external_id
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
custom_comments: [ "COMM001" ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one_with_custom_key_and_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, key: :custom_comment, embed_key: :external_id
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
custom_comment: "COMM001"
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_objects_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, embed: :objects
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, embed: :ids
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
comment_ids: [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_false_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, embed: false
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({}, @hash)
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_include_true_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, embed: :ids, include: true
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
comment_ids: [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_for_has_one_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, embed: :ids
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({
|
||||
comment_id: 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_false_for_has_one_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, embed: false
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({}, @hash)
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_include_true_for_has_one_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, embed: :ids, include: true
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({
|
||||
comment_id: 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_include_true_does_not_serialize_multiple_times
|
||||
@post.recent_comment = @comment
|
||||
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, embed: :ids, include: true
|
||||
has_one :recent_comment, embed: :ids, include: true, root: :comments
|
||||
end
|
||||
|
||||
# Count how often the @comment record is serialized.
|
||||
serialized_times = 0
|
||||
@comment.class_eval do
|
||||
define_method :read_attribute_for_serialization, lambda { |name|
|
||||
serialized_times += 1 if name == :body
|
||||
super(name)
|
||||
}
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
include_bare! :recent_comment
|
||||
|
||||
assert_equal 1, serialized_times
|
||||
end
|
||||
|
||||
def test_include_with_read_association_id_for_serialization_hook
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, embed: :ids, include: true
|
||||
end
|
||||
|
||||
association_name = nil
|
||||
@post.class_eval do
|
||||
define_method :read_attribute_for_serialization, lambda { |name|
|
||||
association_name = name
|
||||
send(name)
|
||||
}
|
||||
define_method :comment_id, lambda {
|
||||
@attributes[:comment].id
|
||||
}
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({
|
||||
comment_id: 1
|
||||
}, @hash)
|
||||
end
|
||||
|
||||
def test_include_with_read_association_ids_for_serialization_hook
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, embed: :ids, include: false
|
||||
end
|
||||
|
||||
association_name = nil
|
||||
@post.class_eval do
|
||||
define_method :read_attribute_for_serialization, lambda { |name|
|
||||
association_name = name
|
||||
send(name)
|
||||
}
|
||||
define_method :comment_ids, lambda {
|
||||
@attributes[:comments].map(&:id)
|
||||
}
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
comment_ids: [1]
|
||||
}, @hash)
|
||||
end
|
||||
end
|
||||
|
||||
class RecursiveTest < AssociationTest
|
||||
class BarSerializer < ActiveModel::Serializer; end
|
||||
|
||||
class FooSerializer < ActiveModel::Serializer
|
||||
root :foos
|
||||
attributes :id
|
||||
has_many :bars, serializer: BarSerializer, root: :bars, embed: :ids, include: true
|
||||
end
|
||||
|
||||
class BarSerializer < ActiveModel::Serializer
|
||||
root :bars
|
||||
attributes :id
|
||||
has_many :foos, serializer: FooSerializer, root: :foos, embed: :ids, include: true
|
||||
end
|
||||
|
||||
class Foo < Model
|
||||
def active_model_serializer; FooSerializer; end
|
||||
end
|
||||
|
||||
class Bar < Model
|
||||
def active_model_serializer; BarSerializer; end
|
||||
end
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
foo = Foo.new(id: 1)
|
||||
bar = Bar.new(id: 2)
|
||||
|
||||
foo.bars = [ bar ]
|
||||
bar.foos = [ foo ]
|
||||
|
||||
collection = [ foo ]
|
||||
|
||||
@serializer = collection.active_model_serializer.new(collection, root: :foos)
|
||||
end
|
||||
|
||||
def test_mutual_relation_result
|
||||
assert_equal({
|
||||
foos: [{
|
||||
bar_ids: [ 2 ],
|
||||
id: 1
|
||||
}],
|
||||
bars: [{
|
||||
foo_ids: [ 1 ],
|
||||
id: 2
|
||||
}]
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_mutual_relation_does_not_raise_error
|
||||
assert_nothing_raised SystemStackError, 'stack level too deep' do
|
||||
@serializer.as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class InclusionTest < AssociationTest
|
||||
def setup
|
||||
super
|
||||
|
||||
comment_serializer_class = @comment_serializer_class
|
||||
|
||||
@post_serializer_class.class_eval do
|
||||
root :post
|
||||
embed :ids, include: true
|
||||
has_many :comments, serializer: comment_serializer_class
|
||||
end
|
||||
end
|
||||
|
||||
def test_when_it_is_included
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, include: [:comments]
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
post: {
|
||||
title: "New Post",
|
||||
body: "Body",
|
||||
comment_ids: [ 1 ]
|
||||
},
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, json)
|
||||
end
|
||||
|
||||
def test_when_it_is_not_included
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, include: []
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
post: {
|
||||
title: "New Post",
|
||||
body: "Body",
|
||||
comment_ids: [ 1 ]
|
||||
}
|
||||
}, json)
|
||||
end
|
||||
|
||||
def test_when_it_is_excluded
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, exclude: [:comments]
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
post: {
|
||||
title: "New Post",
|
||||
body: "Body",
|
||||
comment_ids: [ 1 ]
|
||||
}
|
||||
}, json)
|
||||
end
|
||||
|
||||
def test_when_it_is_not_excluded
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, exclude: []
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
post: {
|
||||
title: "New Post",
|
||||
body: "Body",
|
||||
comment_ids: [ 1 ]
|
||||
},
|
||||
comments: [
|
||||
{ id: 1, external_id: "COMM001", body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, json)
|
||||
end
|
||||
end
|
||||
|
||||
class StringSerializerOption < AssociationTest
|
||||
class StringSerializer < ActiveModel::Serializer
|
||||
attributes :id, :body
|
||||
end
|
||||
|
||||
def test_specifying_serializer_class_as_string
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, embed: :objects
|
||||
end
|
||||
|
||||
include_bare! :comments, serializer: "AssociationTest::StringSerializerOption::StringSerializer"
|
||||
|
||||
assert_equal({
|
||||
comments: [
|
||||
{ id: 1, body: "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,96 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class CachingTest < ActiveModel::TestCase
|
||||
class NullStore
|
||||
def fetch(key)
|
||||
return store[key] if store[key]
|
||||
|
||||
store[key] = yield
|
||||
end
|
||||
|
||||
def clear
|
||||
store.clear
|
||||
end
|
||||
|
||||
def store
|
||||
@store ||= {}
|
||||
end
|
||||
|
||||
def read(key)
|
||||
store[key]
|
||||
end
|
||||
end
|
||||
|
||||
class Programmer
|
||||
def name
|
||||
'Adam'
|
||||
end
|
||||
|
||||
def skills
|
||||
%w(ruby)
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
send name
|
||||
end
|
||||
end
|
||||
|
||||
def test_serializers_have_a_cache_store
|
||||
ActiveModel::Serializer.cache = NullStore.new
|
||||
|
||||
assert_kind_of NullStore, ActiveModel::Serializer.cache
|
||||
end
|
||||
|
||||
def test_serializers_can_enable_caching
|
||||
serializer = Class.new(ActiveModel::Serializer) do
|
||||
cached true
|
||||
end
|
||||
|
||||
assert serializer.perform_caching
|
||||
end
|
||||
|
||||
def test_serializers_use_cache
|
||||
serializer = Class.new(ActiveModel::Serializer) do
|
||||
cached true
|
||||
attributes :name, :skills
|
||||
|
||||
def self.to_s
|
||||
'serializer'
|
||||
end
|
||||
|
||||
def cache_key
|
||||
object.name
|
||||
end
|
||||
end
|
||||
|
||||
serializer.cache = NullStore.new
|
||||
instance = serializer.new Programmer.new
|
||||
|
||||
instance.to_json
|
||||
|
||||
assert_equal(instance.serializable_hash, serializer.cache.read('serializer/Adam/serialize'))
|
||||
assert_equal(instance.to_json, serializer.cache.read('serializer/Adam/to-json'))
|
||||
end
|
||||
|
||||
def test_array_serializer_uses_cache
|
||||
serializer = Class.new(ActiveModel::ArraySerializer) do
|
||||
cached true
|
||||
|
||||
def self.to_s
|
||||
'array_serializer'
|
||||
end
|
||||
|
||||
def cache_key
|
||||
'cache-key'
|
||||
end
|
||||
end
|
||||
|
||||
serializer.cache = NullStore.new
|
||||
instance = serializer.new [Programmer.new]
|
||||
|
||||
instance.to_json
|
||||
|
||||
assert_equal instance.serializable_array, serializer.cache.read('array_serializer/cache-key/serialize')
|
||||
assert_equal instance.to_json, serializer.cache.read('array_serializer/cache-key/to-json')
|
||||
end
|
||||
end
|
||||
12
test/coverage_setup.rb
Normal file
12
test/coverage_setup.rb
Normal file
@ -0,0 +1,12 @@
|
||||
require 'simplecov'
|
||||
require 'coveralls'
|
||||
|
||||
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
||||
SimpleCov::Formatter::HTMLFormatter,
|
||||
Coveralls::SimpleCov::Formatter
|
||||
]
|
||||
|
||||
SimpleCov.start do
|
||||
add_group "lib", "lib"
|
||||
add_group "test", "test"
|
||||
end
|
||||
92
test/fixtures/active_record.rb
vendored
Normal file
92
test/fixtures/active_record.rb
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
require 'active_record'
|
||||
|
||||
ActiveRecord::Base.establish_connection(
|
||||
:adapter => 'sqlite3',
|
||||
:database => ':memory:'
|
||||
)
|
||||
|
||||
ActiveRecord::Schema.define do
|
||||
create_table :ar_posts, force: true do |t|
|
||||
t.string :title
|
||||
t.text :body
|
||||
t.belongs_to :ar_section, index: true
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table :ar_comments, force: true do |t|
|
||||
t.text :body
|
||||
t.belongs_to :ar_post, index: true
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table :ar_tags, force: true do |t|
|
||||
t.string :name
|
||||
end
|
||||
|
||||
create_table :ar_sections, force: true do |t|
|
||||
t.string :name
|
||||
end
|
||||
|
||||
create_table :ar_posts_tags, force: true do |t|
|
||||
t.references :ar_post, :ar_tag, index: true
|
||||
end
|
||||
|
||||
create_table :ar_comments_tags, force: true do |t|
|
||||
t.references :ar_comment, :ar_tag, index: true
|
||||
end
|
||||
end
|
||||
|
||||
class ARPost < ActiveRecord::Base
|
||||
has_many :ar_comments, class_name: 'ARComment'
|
||||
has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_posts_tags
|
||||
belongs_to :ar_section, class_name: 'ARSection'
|
||||
end
|
||||
|
||||
class ARComment < ActiveRecord::Base
|
||||
belongs_to :ar_post, class_name: 'ARPost'
|
||||
has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_comments_tags
|
||||
end
|
||||
|
||||
class ARTag < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class ARSection < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class ARPostSerializer < ActiveModel::Serializer
|
||||
attributes :title, :body
|
||||
|
||||
has_many :ar_comments, :ar_tags
|
||||
has_one :ar_section
|
||||
end
|
||||
|
||||
class ARCommentSerializer < ActiveModel::Serializer
|
||||
attributes :body
|
||||
|
||||
has_many :ar_tags
|
||||
end
|
||||
|
||||
class ARTagSerializer < ActiveModel::Serializer
|
||||
attributes :name
|
||||
end
|
||||
|
||||
class ARSectionSerializer < ActiveModel::Serializer
|
||||
attributes :name
|
||||
end
|
||||
|
||||
ARPost.create(title: 'New post',
|
||||
body: 'A body!!!',
|
||||
ar_section: ARSection.create(name: 'ruby')).tap do |post|
|
||||
|
||||
short_tag = post.ar_tags.create(name: 'short')
|
||||
whiny_tag = post.ar_tags.create(name: 'whiny')
|
||||
happy_tag = post.ar_tags.create(name: 'happy')
|
||||
|
||||
post.ar_comments.create(body: 'what a dumb post').tap do |comment|
|
||||
comment.ar_tags.concat short_tag, whiny_tag
|
||||
end
|
||||
|
||||
post.ar_comments.create(body: 'i liked it').tap do |comment|
|
||||
comment.ar_tags.concat short_tag, happy_tag
|
||||
end
|
||||
end
|
||||
64
test/fixtures/poro.rb
vendored
Normal file
64
test/fixtures/poro.rb
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
class Model
|
||||
def initialize(hash={})
|
||||
@attributes = hash
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
if name == :id || name == 'id'
|
||||
object_id
|
||||
else
|
||||
@attributes[name]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
###
|
||||
## Models
|
||||
###
|
||||
class User < Model
|
||||
def profile
|
||||
@profile ||= Profile.new(name: 'N1', description: 'D1')
|
||||
end
|
||||
end
|
||||
|
||||
class Profile < Model
|
||||
end
|
||||
|
||||
class Post < Model
|
||||
def comments
|
||||
@comments ||= [Comment.new(content: 'C1'),
|
||||
Comment.new(content: 'C2')]
|
||||
end
|
||||
end
|
||||
|
||||
class Comment < Model
|
||||
end
|
||||
|
||||
###
|
||||
## Serializers
|
||||
###
|
||||
class UserSerializer < ActiveModel::Serializer
|
||||
attributes :name, :email
|
||||
|
||||
has_one :profile
|
||||
end
|
||||
|
||||
class ProfileSerializer < ActiveModel::Serializer
|
||||
def description
|
||||
description = object.read_attribute_for_serialization(:description)
|
||||
scope ? "#{description} - #{scope}" : description
|
||||
end
|
||||
|
||||
attributes :name, :description
|
||||
end
|
||||
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :title, :body
|
||||
|
||||
has_many :comments
|
||||
end
|
||||
|
||||
class CommentSerializer < ActiveModel::Serializer
|
||||
attributes :content
|
||||
end
|
||||
@ -1,73 +0,0 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Foo < Rails::Application
|
||||
if Rails.version.to_s.start_with? '4'
|
||||
config.eager_load = false
|
||||
config.secret_key_base = 'abc123'
|
||||
end
|
||||
end
|
||||
|
||||
Rails.application.load_generators
|
||||
|
||||
require 'generators/serializer/serializer_generator'
|
||||
|
||||
class SerializerGeneratorTest < Rails::Generators::TestCase
|
||||
destination File.expand_path("../tmp", __FILE__)
|
||||
setup :prepare_destination
|
||||
|
||||
tests Rails::Generators::SerializerGenerator
|
||||
arguments %w(account name:string description:text business:references)
|
||||
|
||||
def test_generates_a_serializer
|
||||
run_generator
|
||||
assert_file "app/serializers/account_serializer.rb", /class AccountSerializer < ActiveModel::Serializer/
|
||||
end
|
||||
|
||||
def test_generates_a_namespaced_serializer
|
||||
run_generator ["admin/account"]
|
||||
assert_file "app/serializers/admin/account_serializer.rb", /class Admin::AccountSerializer < ActiveModel::Serializer/
|
||||
end
|
||||
|
||||
def test_uses_application_serializer_if_one_exists
|
||||
Object.const_set(:ApplicationSerializer, Class.new)
|
||||
run_generator
|
||||
assert_file "app/serializers/account_serializer.rb", /class AccountSerializer < ApplicationSerializer/
|
||||
ensure
|
||||
Object.send :remove_const, :ApplicationSerializer
|
||||
end
|
||||
|
||||
# def test_uses_namespace_application_serializer_if_one_exists
|
||||
# Object.const_set(:SerializerNamespace, Module.new)
|
||||
# SerializerNamespace.const_set(:ApplicationSerializer, Class.new)
|
||||
# Rails::Generators.namespace = SerializerNamespace
|
||||
# run_generator
|
||||
# assert_file "app/serializers/serializer_namespace/account_serializer.rb",
|
||||
# /module SerializerNamespace\n class AccountSerializer < ApplicationSerializer/
|
||||
# ensure
|
||||
# Object.send :remove_const, :SerializerNamespace
|
||||
# Rails::Generators.namespace = nil
|
||||
# end
|
||||
|
||||
def test_uses_given_parent
|
||||
Object.const_set(:ApplicationSerializer, Class.new)
|
||||
run_generator ["Account", "--parent=MySerializer"]
|
||||
assert_file "app/serializers/account_serializer.rb", /class AccountSerializer < MySerializer/
|
||||
ensure
|
||||
Object.send :remove_const, :ApplicationSerializer
|
||||
end
|
||||
|
||||
def test_generates_attributes_and_associations
|
||||
run_generator
|
||||
assert_file "app/serializers/account_serializer.rb" do |serializer|
|
||||
assert_match(/^ attributes :id, :name, :description$/, serializer)
|
||||
assert_match(/^ has_one :business$/, serializer)
|
||||
end
|
||||
end
|
||||
|
||||
def test_with_no_attributes_does_not_add_extra_space
|
||||
run_generator ["account"]
|
||||
assert_file "app/serializers/account_serializer.rb" do |content|
|
||||
assert_no_match /\n\nend/, content
|
||||
end
|
||||
end
|
||||
end
|
||||
181
test/integration/action_controller/serialization_test.rb
Normal file
181
test/integration/action_controller/serialization_test.rb
Normal file
@ -0,0 +1,181 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActionController
|
||||
module Serialization
|
||||
class ImplicitSerializerTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def render_using_implicit_serializer
|
||||
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
end
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_using_implicit_serializer
|
||||
get :render_using_implicit_serializer
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"profile":{"name":"Name 1","description":"Description 1"}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class ImplicitSerializerScopeTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def render_using_implicit_serializer_and_scope
|
||||
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
'current_user'
|
||||
end
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_using_implicit_serializer_and_scope
|
||||
get :render_using_implicit_serializer_and_scope
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_user"}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultOptionsForSerializerScopeTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def default_serializer_options
|
||||
{ scope: current_admin }
|
||||
end
|
||||
|
||||
def render_using_scope_set_in_default_serializer_options
|
||||
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
'current_user'
|
||||
end
|
||||
|
||||
def current_admin
|
||||
'current_admin'
|
||||
end
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_using_scope_set_in_default_serializer_options
|
||||
get :render_using_scope_set_in_default_serializer_options
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_admin"}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class ExplicitSerializerScopeTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def render_using_implicit_serializer_and_explicit_scope
|
||||
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }), scope: current_admin
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
'current_user'
|
||||
end
|
||||
|
||||
def current_admin
|
||||
'current_admin'
|
||||
end
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_using_implicit_serializer_and_explicit_scope
|
||||
get :render_using_implicit_serializer_and_explicit_scope
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_admin"}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class OverridingSerializationScopeTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def render_overriding_serialization_scope
|
||||
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
'current_user'
|
||||
end
|
||||
|
||||
def serialization_scope
|
||||
'current_admin'
|
||||
end
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_overriding_serialization_scope
|
||||
get :render_overriding_serialization_scope
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_admin"}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class CallingSerializationScopeTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def render_calling_serialization_scope
|
||||
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
'current_user'
|
||||
end
|
||||
|
||||
serialization_scope :current_user
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_calling_serialization_scope
|
||||
get :render_calling_serialization_scope
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_user"}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class RailsSerializerTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def render_using_rails_behavior
|
||||
render json: JSON.dump(hello: 'world')
|
||||
end
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_using_rails_behavior
|
||||
get :render_using_rails_behavior
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class ArraySerializerTest < ActionController::TestCase
|
||||
class MyController < ActionController::Base
|
||||
def render_array
|
||||
render json: [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })]
|
||||
end
|
||||
end
|
||||
|
||||
tests MyController
|
||||
|
||||
def test_render_array
|
||||
get :render_array
|
||||
assert_equal 'application/json', @response.content_type
|
||||
assert_equal '{"my":[{"name":"Name 1","description":"Description 1"}]}', @response.body
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
75
test/integration/active_record/active_record_test.rb
Normal file
75
test/integration/active_record/active_record_test.rb
Normal file
@ -0,0 +1,75 @@
|
||||
require 'test_helper'
|
||||
require 'fixtures/active_record'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class ActiveRecordTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@post = ARPost.first
|
||||
end
|
||||
|
||||
def test_serialization_embedding_objects
|
||||
post_serializer = ARPostSerializer.new(@post)
|
||||
|
||||
assert_equal({
|
||||
'ar_post' => {
|
||||
title: 'New post', body: 'A body!!!',
|
||||
ar_comments: [{ body: 'what a dumb post', ar_tags: [{ name: 'short' }, { name: 'whiny' }] },
|
||||
{ body: 'i liked it', ar_tags: [{:name=>"short"}, {:name=>"happy"}] }],
|
||||
ar_tags: [{ name: 'short' }, { name: 'whiny' }, { name: 'happy' }],
|
||||
ar_section: { name: 'ruby' }
|
||||
}
|
||||
}, post_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_serialization_embedding_ids
|
||||
post_serializer = ARPostSerializer.new(@post)
|
||||
|
||||
embed(ARPostSerializer, embed: :ids) do
|
||||
assert_equal({
|
||||
'ar_post' => {
|
||||
title: 'New post', body: 'A body!!!',
|
||||
'ar_comment_ids' => [1, 2],
|
||||
'ar_tag_ids' => [1, 2, 3],
|
||||
'ar_section_id' => 1
|
||||
}
|
||||
}, post_serializer.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
def test_serialization_embedding_ids_including_in_root
|
||||
post_serializer = ARPostSerializer.new(@post)
|
||||
|
||||
embed(ARPostSerializer, embed: :ids, include: true) do
|
||||
assert_equal({
|
||||
'ar_post' => {
|
||||
title: 'New post', body: 'A body!!!',
|
||||
'ar_comment_ids' => [1, 2],
|
||||
'ar_tag_ids' => [1, 2, 3],
|
||||
'ar_section_id' => 1
|
||||
},
|
||||
ar_comments: [{ body: 'what a dumb post', ar_tags: [{ name: 'short' }, { name: 'whiny' }] },
|
||||
{ body: 'i liked it', ar_tags: [{:name=>"short"}, {:name=>"happy"}] }],
|
||||
ar_tags: [{ name: 'short' }, { name: 'whiny' }, { name: 'happy' }],
|
||||
ar_section: { name: 'ruby' }
|
||||
}, post_serializer.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def embed(klass, options = {})
|
||||
old_assocs = Hash[ARPostSerializer._associations.to_a.map { |(name, association)| [name, association.dup] }]
|
||||
|
||||
ARPostSerializer._associations.each_value do |association|
|
||||
association.embed = options[:embed]
|
||||
association.embed_in_root = options[:include]
|
||||
end
|
||||
|
||||
yield
|
||||
ensure
|
||||
ARPostSerializer._associations = old_assocs
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
27
test/integration/generators/resource_generator_test.rb
Normal file
27
test/integration/generators/resource_generator_test.rb
Normal file
@ -0,0 +1,27 @@
|
||||
require 'test_helper'
|
||||
require 'rails'
|
||||
require 'test_app'
|
||||
require 'rails/generators/rails/resource/resource_generator'
|
||||
require 'active_model/serializer/generators/resource_override'
|
||||
|
||||
class ResourceGeneratorTest < Rails::Generators::TestCase
|
||||
destination File.expand_path('../../../tmp', __FILE__)
|
||||
setup :prepare_destination, :copy_routes
|
||||
|
||||
tests Rails::Generators::ResourceGenerator
|
||||
arguments %w(account)
|
||||
|
||||
def test_serializer_file_is_generated
|
||||
run_generator
|
||||
|
||||
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ActiveModel::Serializer/
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def copy_routes
|
||||
config_dir = File.join(destination_root, 'config')
|
||||
FileUtils.mkdir_p(config_dir)
|
||||
File.write(File.join(config_dir, 'routes.rb'), 'Rails.application.routes.draw { }')
|
||||
end
|
||||
end
|
||||
41
test/integration/generators/serializer_generator_test.rb
Normal file
41
test/integration/generators/serializer_generator_test.rb
Normal file
@ -0,0 +1,41 @@
|
||||
require 'test_helper'
|
||||
require 'rails'
|
||||
require 'test_app'
|
||||
require 'active_model/serializer/generators/serializer/serializer_generator'
|
||||
|
||||
class SerializerGeneratorTest < Rails::Generators::TestCase
|
||||
destination File.expand_path('../../../tmp', __FILE__)
|
||||
setup :prepare_destination
|
||||
|
||||
tests Rails::Generators::SerializerGenerator
|
||||
arguments %w(account name:string description:text business:references)
|
||||
|
||||
def test_generates_a_serializer_with_attributes_and_associations
|
||||
run_generator
|
||||
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ActiveModel::Serializer/ do |serializer|
|
||||
assert_match(/attributes :id, :name, :description/, serializer)
|
||||
assert_match(/has_one :business/, serializer)
|
||||
end
|
||||
end
|
||||
|
||||
def test_generates_a_namespaced_serializer
|
||||
run_generator ['admin/account']
|
||||
assert_file 'app/serializers/admin/account_serializer.rb', /class Admin::AccountSerializer < ActiveModel::Serializer/
|
||||
end
|
||||
|
||||
def test_uses_application_serializer_if_one_exists
|
||||
Object.const_set(:ApplicationSerializer, Class.new)
|
||||
run_generator
|
||||
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ApplicationSerializer/
|
||||
ensure
|
||||
Object.send :remove_const, :ApplicationSerializer
|
||||
end
|
||||
|
||||
def test_uses_given_parent
|
||||
Object.const_set(:ApplicationSerializer, Class.new)
|
||||
run_generator ['Account', '--parent=MySerializer']
|
||||
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < MySerializer/
|
||||
ensure
|
||||
Object.send :remove_const, :ApplicationSerializer
|
||||
end
|
||||
end
|
||||
@ -1,34 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class NoSerializationScopeTest < ActionController::TestCase
|
||||
class ScopeSerializer
|
||||
def initialize(object, options)
|
||||
@object, @options = object, options
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ scope: @options[:scope].as_json }
|
||||
end
|
||||
end
|
||||
|
||||
class ScopeSerializable
|
||||
def active_model_serializer
|
||||
ScopeSerializer
|
||||
end
|
||||
end
|
||||
|
||||
class NoSerializationScopeController < ActionController::Base
|
||||
serialization_scope nil
|
||||
|
||||
def index
|
||||
render json: ScopeSerializable.new
|
||||
end
|
||||
end
|
||||
|
||||
tests NoSerializationScopeController
|
||||
|
||||
def test_disabled_serialization_scope
|
||||
get :index, format: :json
|
||||
assert_equal '{"scope":null}', @response.body
|
||||
end
|
||||
end
|
||||
@ -1,99 +0,0 @@
|
||||
require 'test_helper'
|
||||
require 'pathname'
|
||||
|
||||
class DefaultScopeNameTest < ActionController::TestCase
|
||||
TestUser = Struct.new(:name, :admin)
|
||||
|
||||
class UserSerializer < ActiveModel::Serializer
|
||||
attributes :admin?
|
||||
def admin?
|
||||
current_user.admin
|
||||
end
|
||||
end
|
||||
|
||||
class UserTestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
before_filter { request.format = :json }
|
||||
|
||||
def current_user
|
||||
TestUser.new('Pete', false)
|
||||
end
|
||||
|
||||
def render_new_user
|
||||
render json: TestUser.new('pete', false), serializer: UserSerializer
|
||||
end
|
||||
end
|
||||
|
||||
tests UserTestController
|
||||
|
||||
def test_default_scope_name
|
||||
get :render_new_user
|
||||
assert_equal '{"user":{"admin":false}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class SerializationScopeNameTest < ActionController::TestCase
|
||||
TestUser = Struct.new(:name, :admin)
|
||||
|
||||
class AdminUserSerializer < ActiveModel::Serializer
|
||||
attributes :admin?
|
||||
def admin?
|
||||
current_admin.admin
|
||||
end
|
||||
end
|
||||
|
||||
class AdminUserTestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
serialization_scope :current_admin
|
||||
before_filter { request.format = :json }
|
||||
|
||||
def current_admin
|
||||
TestUser.new('Bob', true)
|
||||
end
|
||||
|
||||
def render_new_user
|
||||
render json: TestUser.new('pete', false), serializer: AdminUserSerializer
|
||||
end
|
||||
end
|
||||
|
||||
tests AdminUserTestController
|
||||
|
||||
def test_override_scope_name_with_controller
|
||||
get :render_new_user
|
||||
assert_equal '{"admin_user":{"admin":true}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class SerializationActionScopeOverrideTest < ActionController::TestCase
|
||||
TestUser = Struct.new(:name, :admin)
|
||||
|
||||
class AdminUserSerializer < ActiveModel::Serializer
|
||||
attributes :admin?
|
||||
def admin?
|
||||
current_admin.admin
|
||||
end
|
||||
end
|
||||
|
||||
class AdminUserTestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
before_filter { request.format = :json }
|
||||
|
||||
def current_admin
|
||||
TestUser.new('Bob', true)
|
||||
end
|
||||
|
||||
def render_new_user
|
||||
render json: TestUser.new('pete', false), serializer: AdminUserSerializer, scope: current_admin, scope_name: :current_admin
|
||||
end
|
||||
end
|
||||
|
||||
tests AdminUserTestController
|
||||
|
||||
def test_override_scope_name_with_controller
|
||||
get :render_new_user
|
||||
assert_equal '{"admin_user":{"admin":true}}', @response.body
|
||||
end
|
||||
|
||||
end
|
||||
@ -1,394 +0,0 @@
|
||||
require 'test_helper'
|
||||
require 'pathname'
|
||||
|
||||
class RenderJsonTest < ActionController::TestCase
|
||||
class JsonRenderable
|
||||
def as_json(options={})
|
||||
hash = { a: :b, c: :d, e: :f }
|
||||
hash.except!(*options[:except]) if options[:except]
|
||||
hash
|
||||
end
|
||||
|
||||
def to_json(options = {})
|
||||
super except: [:c, :e]
|
||||
end
|
||||
end
|
||||
|
||||
class JsonSerializer
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
hash = { object: serializable_hash, scope: @options[:scope].as_json }
|
||||
hash.merge!(options: true) if @options[:options]
|
||||
hash.merge!(check_defaults: true) if @options[:check_defaults]
|
||||
hash
|
||||
end
|
||||
|
||||
def serializable_hash
|
||||
@object.as_json
|
||||
end
|
||||
end
|
||||
|
||||
class JsonSerializable
|
||||
def initialize(skip=false)
|
||||
@skip = skip
|
||||
end
|
||||
|
||||
def active_model_serializer
|
||||
JsonSerializer unless @skip
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ serializable_object: true }
|
||||
end
|
||||
end
|
||||
|
||||
class CustomSerializer
|
||||
def initialize(*)
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ hello: true }
|
||||
end
|
||||
end
|
||||
|
||||
class AnotherCustomSerializer
|
||||
def initialize(*)
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ rails: 'rocks' }
|
||||
end
|
||||
end
|
||||
|
||||
class DummyCustomSerializer < ActiveModel::Serializer
|
||||
attributes :id
|
||||
end
|
||||
|
||||
class HypermediaSerializable
|
||||
def active_model_serializer
|
||||
HypermediaSerializer
|
||||
end
|
||||
end
|
||||
|
||||
class HypermediaSerializer < ActiveModel::Serializer
|
||||
def as_json(*)
|
||||
{ link: hypermedia_url }
|
||||
end
|
||||
end
|
||||
|
||||
class CustomArraySerializer < ActiveModel::ArraySerializer
|
||||
self.root = "items"
|
||||
end
|
||||
|
||||
class TestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
serialization_scope :current_user
|
||||
attr_reader :current_user
|
||||
|
||||
def self.controller_path
|
||||
'test'
|
||||
end
|
||||
|
||||
def render_json_nil
|
||||
render json: nil
|
||||
end
|
||||
|
||||
def render_json_render_to_string
|
||||
render text: render_to_string(json: '[]')
|
||||
end
|
||||
|
||||
def render_json_hello_world
|
||||
render json: ActiveSupport::JSON.encode(hello: 'world')
|
||||
end
|
||||
|
||||
def render_json_hello_world_with_status
|
||||
render json: ActiveSupport::JSON.encode(hello: 'world'), status: 401
|
||||
end
|
||||
|
||||
def render_json_hello_world_with_callback
|
||||
render json: ActiveSupport::JSON.encode(hello: 'world'), callback: 'alert'
|
||||
end
|
||||
|
||||
def render_json_with_custom_content_type
|
||||
render json: ActiveSupport::JSON.encode(hello: 'world'), content_type: 'text/javascript'
|
||||
end
|
||||
|
||||
def render_symbol_json
|
||||
render json: ActiveSupport::JSON.encode(hello: 'world')
|
||||
end
|
||||
|
||||
def render_json_nil_with_custom_serializer
|
||||
render json: nil, serializer: DummyCustomSerializer
|
||||
end
|
||||
|
||||
|
||||
def render_json_with_extra_options
|
||||
render json: JsonRenderable.new, except: [:c, :e]
|
||||
end
|
||||
|
||||
def render_json_without_options
|
||||
render json: JsonRenderable.new
|
||||
end
|
||||
|
||||
def render_json_with_serializer
|
||||
@current_user = Struct.new(:as_json).new(current_user: true)
|
||||
render json: JsonSerializable.new
|
||||
end
|
||||
|
||||
def render_json_with_serializer_and_implicit_root
|
||||
@current_user = Struct.new(:as_json).new(current_user: true)
|
||||
render json: [JsonSerializable.new]
|
||||
end
|
||||
|
||||
def render_json_with_serializer_and_options
|
||||
@current_user = Struct.new(:as_json).new(current_user: true)
|
||||
render json: JsonSerializable.new, options: true
|
||||
end
|
||||
|
||||
def render_json_with_serializer_and_scope_option
|
||||
@current_user = Struct.new(:as_json).new(current_user: true)
|
||||
scope = Struct.new(:as_json).new(current_user: false)
|
||||
render json: JsonSerializable.new, scope: scope
|
||||
end
|
||||
|
||||
def render_json_with_serializer_api_but_without_serializer
|
||||
@current_user = Struct.new(:as_json).new(current_user: true)
|
||||
render json: JsonSerializable.new(true)
|
||||
end
|
||||
|
||||
# To specify a custom serializer for an object, use :serializer.
|
||||
def render_json_with_custom_serializer
|
||||
render json: Object.new, serializer: CustomSerializer
|
||||
end
|
||||
|
||||
# To specify a custom serializer for each item in the Array, use :each_serializer.
|
||||
def render_json_array_with_custom_serializer
|
||||
render json: [Object.new], each_serializer: CustomSerializer
|
||||
end
|
||||
|
||||
def render_json_array_with_wrong_option
|
||||
render json: [Object.new], serializer: CustomSerializer
|
||||
end
|
||||
|
||||
def render_json_with_links
|
||||
render json: HypermediaSerializable.new
|
||||
end
|
||||
|
||||
def render_json_array_with_no_root
|
||||
render json: [], root: false
|
||||
end
|
||||
|
||||
def render_json_empty_array
|
||||
render json: []
|
||||
end
|
||||
|
||||
def render_json_array_with_custom_array_serializer
|
||||
render json: [], serializer: CustomArraySerializer
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def default_serializer_options
|
||||
defaults = {}
|
||||
defaults.merge!(check_defaults: true) if params[:check_defaults]
|
||||
defaults.merge!(root: :awesome) if params[:check_default_root]
|
||||
defaults.merge!(scope: :current_admin) if params[:check_default_scope]
|
||||
defaults.merge!(serializer: AnotherCustomSerializer) if params[:check_default_serializer]
|
||||
defaults.merge!(each_serializer: AnotherCustomSerializer) if params[:check_default_each_serializer]
|
||||
defaults
|
||||
end
|
||||
end
|
||||
|
||||
tests TestController
|
||||
|
||||
def setup
|
||||
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
|
||||
# a more accurate simulation of what happens in "real life".
|
||||
super
|
||||
@controller.logger = Logger.new(nil)
|
||||
|
||||
@request.host = "www.nextangle.com"
|
||||
end
|
||||
|
||||
def test_render_json_nil
|
||||
get :render_json_nil
|
||||
assert_equal 'null', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_render_to_string
|
||||
get :render_json_render_to_string
|
||||
assert_equal '[]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_nil_with_custom_serializer
|
||||
get :render_json_nil_with_custom_serializer
|
||||
assert_equal "{\"dummy_custom\":null}", @response.body
|
||||
end
|
||||
|
||||
def test_render_json
|
||||
get :render_json_hello_world
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_with_status
|
||||
get :render_json_hello_world_with_status
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 401, @response.status
|
||||
end
|
||||
|
||||
def test_render_json_with_callback
|
||||
get :render_json_hello_world_with_callback
|
||||
assert_equal 'alert({"hello":"world"})', @response.body
|
||||
# For JSONP, Rails 3 uses application/json, but Rails 4 uses text/javascript
|
||||
assert_match %r(application/json|text/javascript), @response.content_type.to_s
|
||||
end
|
||||
|
||||
def test_render_json_with_custom_content_type
|
||||
get :render_json_with_custom_content_type
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 'text/javascript', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_symbol_json
|
||||
get :render_symbol_json
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_forwards_extra_options
|
||||
get :render_json_with_extra_options
|
||||
assert_equal '{"a":"b"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_calls_to_json_from_object
|
||||
get :render_json_without_options
|
||||
assert_equal '{"a":"b"}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer
|
||||
get :render_json_with_serializer
|
||||
assert_match '"scope":{"current_user":true}', @response.body
|
||||
assert_match '"object":{"serializable_object":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_checking_defaults
|
||||
get :render_json_with_serializer, check_defaults: true
|
||||
assert_match '"scope":{"current_user":true}', @response.body
|
||||
assert_match '"object":{"serializable_object":true}', @response.body
|
||||
assert_match '"check_defaults":true', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_checking_default_serailizer
|
||||
get :render_json_with_serializer, check_default_serializer: true
|
||||
assert_match '{"rails":"rocks"}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_checking_default_scope
|
||||
get :render_json_with_serializer, check_default_scope: true
|
||||
assert_match '"scope":"current_admin"', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_implicit_root
|
||||
get :render_json_with_serializer_and_implicit_root
|
||||
assert_match '"test":[{"serializable_object":true}]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_implicit_root_checking_default_each_serailizer
|
||||
get :render_json_with_serializer_and_implicit_root, check_default_each_serializer: true
|
||||
assert_match '"test":[{"rails":"rocks"}]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_options
|
||||
get :render_json_with_serializer_and_options
|
||||
assert_match '"scope":{"current_user":true}', @response.body
|
||||
assert_match '"object":{"serializable_object":true}', @response.body
|
||||
assert_match '"options":true', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_scope_option
|
||||
get :render_json_with_serializer_and_scope_option
|
||||
assert_match '"scope":{"current_user":false}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_scope_option_checking_default_scope
|
||||
get :render_json_with_serializer_and_scope_option, check_default_scope: true
|
||||
assert_match '"scope":{"current_user":false}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_api_but_without_serializer
|
||||
get :render_json_with_serializer_api_but_without_serializer
|
||||
assert_match '{"serializable_object":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_custom_serializer
|
||||
get :render_json_with_custom_serializer
|
||||
assert_match '{"hello":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_custom_serializer_checking_default_serailizer
|
||||
get :render_json_with_custom_serializer, check_default_serializer: true
|
||||
assert_match '{"hello":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_custom_serializer
|
||||
get :render_json_array_with_custom_serializer
|
||||
assert_match '{"test":[{"hello":true}]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_wrong_option
|
||||
assert_raise ArgumentError do
|
||||
get :render_json_array_with_wrong_option
|
||||
end
|
||||
end
|
||||
|
||||
def test_render_json_array_with_custom_serializer_checking_default_each_serailizer
|
||||
get :render_json_array_with_custom_serializer, check_default_each_serializer: true
|
||||
assert_match '{"test":[{"hello":true}]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_links
|
||||
get :render_json_with_links
|
||||
assert_match '{"link":"http://www.nextangle.com/hypermedia"}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_no_root
|
||||
get :render_json_array_with_no_root
|
||||
assert_equal '[]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_no_root_checking_default_root
|
||||
get :render_json_array_with_no_root, check_default_root: true
|
||||
assert_equal '[]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_empty_array
|
||||
get :render_json_empty_array
|
||||
assert_equal '{"test":[]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_empty_array_checking_default_root
|
||||
get :render_json_empty_array, check_default_root: true
|
||||
assert_equal '{"awesome":[]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_empty_array_with_array_serializer_root_false
|
||||
ActiveModel::ArraySerializer.root = false
|
||||
get :render_json_empty_array
|
||||
assert_equal '[]', @response.body
|
||||
ensure # teardown
|
||||
ActiveModel::ArraySerializer.root = nil
|
||||
end
|
||||
|
||||
def test_render_json_array_with_custom_array_serializer
|
||||
get :render_json_array_with_custom_array_serializer
|
||||
assert_equal '{"items":[]}', @response.body
|
||||
end
|
||||
|
||||
end
|
||||
@ -1,51 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class RandomModel
|
||||
include ActiveModel::SerializerSupport
|
||||
end
|
||||
|
||||
class OtherRandomModel
|
||||
include ActiveModel::SerializerSupport
|
||||
end
|
||||
|
||||
class OtherRandomModelSerializer
|
||||
end
|
||||
|
||||
class RandomModelCollection
|
||||
include ActiveModel::ArraySerializerSupport
|
||||
end
|
||||
|
||||
module ActiveRecord
|
||||
class Relation
|
||||
end
|
||||
end
|
||||
|
||||
module Mongoid
|
||||
class Criteria
|
||||
end
|
||||
end
|
||||
|
||||
class SerializerSupportTest < ActiveModel::TestCase
|
||||
test "it returns nil if no serializer exists" do
|
||||
assert_equal nil, RandomModel.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it returns a deducted serializer if it exists exists" do
|
||||
assert_equal OtherRandomModelSerializer, OtherRandomModel.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it returns ArraySerializer for a collection" do
|
||||
assert_equal ActiveModel::ArraySerializer, RandomModelCollection.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it automatically includes array_serializer in active_record/relation" do
|
||||
ActiveSupport.run_load_hooks(:active_record)
|
||||
assert_equal ActiveModel::ArraySerializer, ActiveRecord::Relation.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it automatically includes array_serializer in mongoid/criteria" do
|
||||
ActiveSupport.run_load_hooks(:mongoid)
|
||||
assert_equal ActiveModel::ArraySerializer, Mongoid::Criteria.new.active_model_serializer
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
8
test/test_app.rb
Normal file
8
test/test_app.rb
Normal file
@ -0,0 +1,8 @@
|
||||
class TestApp < Rails::Application
|
||||
if Rails.version.to_s.first >= '4'
|
||||
config.eager_load = false
|
||||
config.secret_key_base = 'abc123'
|
||||
end
|
||||
end
|
||||
|
||||
TestApp.load_generators
|
||||
@ -1,202 +0,0 @@
|
||||
class Model
|
||||
def initialize(hash={})
|
||||
@attributes = hash
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
@attributes[name]
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ model: "Model" }
|
||||
end
|
||||
end
|
||||
|
||||
class ModelWithActiveModelSerializer < Model
|
||||
include ActiveModel::Serializers::JSON
|
||||
attr_accessor :attributes
|
||||
def read_attribute_for_serialization(name)
|
||||
@attributes[name]
|
||||
end
|
||||
end
|
||||
|
||||
class User
|
||||
include ActiveModel::SerializerSupport
|
||||
|
||||
attr_accessor :superuser
|
||||
|
||||
def initialize(hash={})
|
||||
@attributes = hash.merge(first_name: "Jose", last_name: "Valim", password: "oh noes yugive my password")
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
@attributes[name]
|
||||
end
|
||||
|
||||
def super_user?
|
||||
@superuser
|
||||
end
|
||||
end
|
||||
|
||||
class Post < Model
|
||||
def initialize(attributes)
|
||||
super(attributes)
|
||||
self.comments ||= []
|
||||
self.comments_disabled = false
|
||||
self.author = nil
|
||||
end
|
||||
|
||||
attr_accessor :comments, :comments_disabled, :author
|
||||
def active_model_serializer; PostSerializer; end
|
||||
end
|
||||
|
||||
class Comment < Model
|
||||
def active_model_serializer; CommentSerializer; end
|
||||
end
|
||||
|
||||
class UserSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(ok: true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class UserAttributesWithKeySerializer < ActiveModel::Serializer
|
||||
attributes first_name: :f_name, last_name: :l_name
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(ok: true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class UserAttributesWithSomeKeySerializer < ActiveModel::Serializer
|
||||
attributes :first_name, last_name: :l_name
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(ok: true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class UserAttributesWithUnsymbolizableKeySerializer < ActiveModel::Serializer
|
||||
attributes :first_name, last_name: :"last-name"
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(ok: true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultUserSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
end
|
||||
|
||||
class MyUserSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
|
||||
def serializable_hash
|
||||
hash = attributes
|
||||
hash = hash.merge(super_user: true) if object.super_user?
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
class CommentSerializer
|
||||
def initialize(comment, options={})
|
||||
@object = comment
|
||||
end
|
||||
|
||||
attr_reader :object
|
||||
|
||||
def serializable_hash
|
||||
{ title: @object.read_attribute_for_serialization(:title) }
|
||||
end
|
||||
|
||||
def as_json(options=nil)
|
||||
options ||= {}
|
||||
if options[:root] == false
|
||||
serializable_hash
|
||||
else
|
||||
{ comment: serializable_hash }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :title, :body
|
||||
has_many :comments, serializer: CommentSerializer
|
||||
end
|
||||
|
||||
class PostWithConditionalCommentsSerializer < ActiveModel::Serializer
|
||||
root :post
|
||||
attributes :title, :body
|
||||
has_many :comments, serializer: CommentSerializer
|
||||
|
||||
def include_associations!
|
||||
include! :comments unless object.comments_disabled
|
||||
end
|
||||
end
|
||||
|
||||
class PostWithMultipleConditionalsSerializer < ActiveModel::Serializer
|
||||
root :post
|
||||
attributes :title, :body, :author
|
||||
has_many :comments, serializer: CommentSerializer
|
||||
|
||||
def include_comments?
|
||||
!object.comments_disabled
|
||||
end
|
||||
|
||||
def include_author?
|
||||
scope.super_user?
|
||||
end
|
||||
end
|
||||
|
||||
class Blog < Model
|
||||
attr_accessor :author
|
||||
end
|
||||
|
||||
class AuthorSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
end
|
||||
|
||||
class BlogSerializer < ActiveModel::Serializer
|
||||
has_one :author, serializer: AuthorSerializer
|
||||
end
|
||||
|
||||
class BlogWithRootSerializer < BlogSerializer
|
||||
root true
|
||||
end
|
||||
|
||||
class CustomPostSerializer < ActiveModel::Serializer
|
||||
attributes :title
|
||||
end
|
||||
|
||||
class CustomBlog < Blog
|
||||
attr_accessor :public_posts, :public_user
|
||||
end
|
||||
|
||||
class CustomBlogSerializer < ActiveModel::Serializer
|
||||
has_many :public_posts, key: :posts, serializer: PostSerializer
|
||||
has_one :public_user, key: :user, serializer: UserSerializer
|
||||
end
|
||||
|
||||
class SomeSerializer < ActiveModel::Serializer
|
||||
attributes :some
|
||||
end
|
||||
|
||||
class SomeObject < Struct.new(:some)
|
||||
end
|
||||
|
||||
# Set up some classes for polymorphic testing
|
||||
class Attachment < Model
|
||||
def attachable
|
||||
@attributes[:attachable]
|
||||
end
|
||||
|
||||
def readable
|
||||
@attributes[:readable]
|
||||
end
|
||||
|
||||
def edible
|
||||
@attributes[:edible]
|
||||
end
|
||||
end
|
||||
@ -1,41 +1,21 @@
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
require 'simplecov'
|
||||
SimpleCov.start do
|
||||
add_group "lib", "lib"
|
||||
add_group "spec", "spec"
|
||||
end
|
||||
|
||||
require 'coveralls'
|
||||
Coveralls.wear!
|
||||
|
||||
require "pry"
|
||||
|
||||
require "active_model_serializers"
|
||||
require "active_support/json"
|
||||
require "minitest/autorun"
|
||||
|
||||
require 'rails'
|
||||
require 'bundler/setup'
|
||||
require 'coverage_setup'
|
||||
require 'minitest/autorun'
|
||||
require 'active_model_serializers'
|
||||
require 'fixtures/poro'
|
||||
|
||||
module TestHelper
|
||||
Routes = ActionDispatch::Routing::RouteSet.new
|
||||
Routes.draw do
|
||||
resource :hypermedia
|
||||
get ':controller(/:action(/:id))'
|
||||
get ':controller(/:action)'
|
||||
end
|
||||
|
||||
ActionController::Base.send :include, Routes.url_helpers
|
||||
ActiveModel::Serializer.send :include, Routes.url_helpers
|
||||
end
|
||||
|
||||
ActiveSupport::TestCase.class_eval do
|
||||
setup do
|
||||
@routes = ::TestHelper::Routes
|
||||
ActionController::TestCase.class_eval do
|
||||
def setup
|
||||
@routes = TestHelper::Routes
|
||||
end
|
||||
end
|
||||
|
||||
class Object
|
||||
undef_method :id if respond_to?(:id)
|
||||
end
|
||||
|
||||
53
test/unit/active_model/array_serializer/meta_test.rb
Normal file
53
test/unit/active_model/array_serializer/meta_test.rb
Normal file
@ -0,0 +1,53 @@
|
||||
require 'test_helper'
|
||||
require 'active_model/serializer'
|
||||
|
||||
module ActiveModel
|
||||
class ArraySerializer
|
||||
class MetaTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@profile1 = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@profile2 = Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
|
||||
@serializer = ArraySerializer.new([@profile1, @profile2], root: 'profiles')
|
||||
end
|
||||
|
||||
def test_meta
|
||||
@serializer.meta = { total: 10 }
|
||||
|
||||
assert_equal({
|
||||
'profiles' => [
|
||||
{
|
||||
name: 'Name 1',
|
||||
description: 'Description 1'
|
||||
}, {
|
||||
name: 'Name 2',
|
||||
description: 'Description 2'
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
total: 10
|
||||
}
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_meta_using_meta_key
|
||||
@serializer.meta_key = :my_meta
|
||||
@serializer.meta = { total: 10 }
|
||||
|
||||
assert_equal({
|
||||
'profiles' => [
|
||||
{
|
||||
name: 'Name 1',
|
||||
description: 'Description 1'
|
||||
}, {
|
||||
name: 'Name 2',
|
||||
description: 'Description 2'
|
||||
}
|
||||
],
|
||||
my_meta: {
|
||||
total: 10
|
||||
}
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
102
test/unit/active_model/array_serializer/root_test.rb
Normal file
102
test/unit/active_model/array_serializer/root_test.rb
Normal file
@ -0,0 +1,102 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class ArraySerializer
|
||||
class RootAsOptionTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@old_root = ArraySerializer._root
|
||||
@profile1 = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@profile2 = Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
|
||||
@serializer = ArraySerializer.new([@profile1, @profile2], root: :initialize)
|
||||
end
|
||||
|
||||
def teardown
|
||||
ArraySerializer._root = @old_root
|
||||
end
|
||||
|
||||
def test_root_is_not_displayed_using_serializable_array
|
||||
assert_equal([
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
], @serializer.serializable_array)
|
||||
end
|
||||
|
||||
def test_root_using_as_json
|
||||
assert_equal({
|
||||
initialize: [
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
]
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_root_as_argument_takes_precedence
|
||||
assert_equal({
|
||||
argument: [
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
]
|
||||
}, @serializer.as_json(root: :argument))
|
||||
end
|
||||
|
||||
def test_using_false_root_in_initialize_takes_precedence
|
||||
ArraySerializer._root = 'root'
|
||||
@serializer = ArraySerializer.new([@profile1, @profile2], root: false)
|
||||
|
||||
assert_equal([
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
], @serializer.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
class RootInSerializerTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@old_root = ArraySerializer._root
|
||||
ArraySerializer._root = :in_serializer
|
||||
@profile1 = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@profile2 = Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
|
||||
@serializer = ArraySerializer.new([@profile1, @profile2])
|
||||
@rooted_serializer = ArraySerializer.new([@profile1, @profile2], root: :initialize)
|
||||
end
|
||||
|
||||
def teardown
|
||||
ArraySerializer._root = @old_root
|
||||
end
|
||||
|
||||
def test_root_is_not_displayed_using_serializable_hash
|
||||
assert_equal([
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
], @serializer.serializable_array)
|
||||
end
|
||||
|
||||
def test_root_using_as_json
|
||||
assert_equal({
|
||||
in_serializer: [
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
]
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_root_in_initializer_takes_precedence
|
||||
assert_equal({
|
||||
initialize: [
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
]
|
||||
}, @rooted_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_root_as_argument_takes_precedence
|
||||
assert_equal({
|
||||
argument: [
|
||||
{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }
|
||||
]
|
||||
}, @rooted_serializer.as_json(root: :argument))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
24
test/unit/active_model/array_serializer/scope_test.rb
Normal file
24
test/unit/active_model/array_serializer/scope_test.rb
Normal file
@ -0,0 +1,24 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class ArraySerializer
|
||||
class ScopeTest < ActiveModel::TestCase
|
||||
def test_array_serializer_pass_options_to_items_serializers
|
||||
array = [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||
serializer = ArraySerializer.new(array, scope: current_user)
|
||||
|
||||
expected = [{ name: 'Name 1', description: 'Description 1 - user' },
|
||||
{ name: 'Name 2', description: 'Description 2 - user' }]
|
||||
|
||||
assert_equal expected, serializer.serializable_array
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
'user'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
45
test/unit/active_model/array_serializer/serialize_test.rb
Normal file
45
test/unit/active_model/array_serializer/serialize_test.rb
Normal file
@ -0,0 +1,45 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class ArraySerializer
|
||||
class SerializeTest < ActiveModel::TestCase
|
||||
def setup
|
||||
array = [1, 2, 3]
|
||||
@serializer = ActiveModel::Serializer.serializer_for(array).new(array)
|
||||
end
|
||||
|
||||
def test_serializer_for_array_returns_appropriate_type
|
||||
assert_kind_of ArraySerializer, @serializer
|
||||
end
|
||||
|
||||
def test_array_serializer_serializes_simple_objects
|
||||
assert_equal [1, 2, 3], @serializer.serializable_array
|
||||
assert_equal [1, 2, 3], @serializer.as_json
|
||||
end
|
||||
|
||||
def test_array_serializer_serializes_models
|
||||
array = [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||
serializer = ArraySerializer.new(array)
|
||||
|
||||
expected = [{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }]
|
||||
|
||||
assert_equal expected, serializer.serializable_array
|
||||
assert_equal expected, serializer.as_json
|
||||
end
|
||||
|
||||
def test_array_serializers_each_serializer
|
||||
array = [::Model.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||
::Model.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||
serializer = ArraySerializer.new(array, each_serializer: ProfileSerializer)
|
||||
|
||||
expected = [{ name: 'Name 1', description: 'Description 1' },
|
||||
{ name: 'Name 2', description: 'Description 2' }]
|
||||
|
||||
assert_equal expected, serializer.serializable_array
|
||||
assert_equal expected, serializer.as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
15
test/unit/active_model/default_serializer_test.rb
Normal file
15
test/unit/active_model/default_serializer_test.rb
Normal file
@ -0,0 +1,15 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class DefaultSerializer
|
||||
class Test < ActiveModel::TestCase
|
||||
def test_serialize_objects
|
||||
assert_equal(nil, DefaultSerializer.new(nil).serializable_hash)
|
||||
assert_equal(1, DefaultSerializer.new(1).serializable_hash)
|
||||
assert_equal('hi', DefaultSerializer.new('hi').serializable_hash)
|
||||
obj = Struct.new(:a, :b).new(1, 2)
|
||||
assert_equal({ a: 1, b: 2 }, DefaultSerializer.new(obj).serializable_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
29
test/unit/active_model/serializer/attributes_test.rb
Normal file
29
test/unit/active_model/serializer/attributes_test.rb
Normal file
@ -0,0 +1,29 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class AttributesTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@profile_serializer = ProfileSerializer.new(@profile)
|
||||
end
|
||||
|
||||
def test_attributes_definition
|
||||
assert_equal([:name, :description],
|
||||
@profile_serializer.class._attributes)
|
||||
end
|
||||
|
||||
def test_attributes_serialization_using_serializable_hash
|
||||
assert_equal({
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}, @profile_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_attributes_serialization_using_as_json
|
||||
assert_equal({
|
||||
'profile' => { name: 'Name 1', description: 'Description 1' }
|
||||
}, @profile_serializer.as_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
49
test/unit/active_model/serializer/filter_test.rb
Normal file
49
test/unit/active_model/serializer/filter_test.rb
Normal file
@ -0,0 +1,49 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class FilterAttributesTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@profile_serializer = ProfileSerializer.new(@profile)
|
||||
@profile_serializer.instance_eval do
|
||||
def filter(keys)
|
||||
keys - [:description]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_filtered_attributes_serialization
|
||||
assert_equal({
|
||||
'profile' => { name: 'Name 1' }
|
||||
}, @profile_serializer.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
class FilterAssociationsTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@association = PostSerializer._associations[:comments]
|
||||
@old_association = @association.dup
|
||||
@association.embed = :ids
|
||||
@association.embed_in_root = true
|
||||
@post = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' })
|
||||
@post_serializer = PostSerializer.new(@post)
|
||||
@post_serializer.instance_eval do
|
||||
def filter(keys)
|
||||
keys - [:body, :comments]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
PostSerializer._associations[:comments] = @old_association
|
||||
end
|
||||
|
||||
def test_filtered_associations_serialization
|
||||
assert_equal({
|
||||
'post' => { title: 'Title 1' }
|
||||
}, @post_serializer.as_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
117
test/unit/active_model/serializer/has_many_test.rb
Normal file
117
test/unit/active_model/serializer/has_many_test.rb
Normal file
@ -0,0 +1,117 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class HasManyTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@association = PostSerializer._associations[:comments]
|
||||
@old_association = @association.dup
|
||||
@association.embed = :ids
|
||||
@post = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' })
|
||||
@post_serializer = PostSerializer.new(@post)
|
||||
end
|
||||
|
||||
def teardown
|
||||
PostSerializer._associations[:comments] = @old_association
|
||||
end
|
||||
|
||||
def test_associations_definition
|
||||
assert_equal 1, PostSerializer._associations.length
|
||||
assert_kind_of Association::HasMany, @association
|
||||
assert_equal 'comments', @association.name
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_serialization_using_serializable_hash
|
||||
assert_equal({
|
||||
title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }
|
||||
}, @post_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_serialization_using_as_json
|
||||
assert_equal({
|
||||
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }
|
||||
}, @post_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options
|
||||
@association.key = 'key'
|
||||
assert_equal({
|
||||
title: 'Title 1', body: 'Body 1', 'key' => @post.comments.map { |c| c.object_id }
|
||||
}, @post_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_objects_serialization_using_serializable_hash
|
||||
@association.embed = :objects
|
||||
assert_equal({
|
||||
title: 'Title 1', body: 'Body 1', comments: [{ content: 'C1' }, { content: 'C2' }]
|
||||
}, @post_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_objects_serialization_using_as_json
|
||||
@association.embed = :objects
|
||||
assert_equal({
|
||||
'post' => { title: 'Title 1', body: 'Body 1', comments: [{ content: 'C1' }, { content: 'C2' }] }
|
||||
}, @post_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_embedding_nil_objects_serialization_using_as_json
|
||||
@association.embed = :objects
|
||||
@post.instance_eval do
|
||||
def comments
|
||||
[nil]
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal({
|
||||
'post' => { title: 'Title 1', body: 'Body 1', comments: [nil] }
|
||||
}, @post_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options
|
||||
@association.embed = :objects
|
||||
@association.embedded_key = 'root'
|
||||
assert_equal({
|
||||
title: 'Title 1', body: 'Body 1', 'root' => [{ content: 'C1' }, { content: 'C2' }]
|
||||
}, @post_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash
|
||||
@association.embed_in_root = true
|
||||
@post_serializer.root = nil
|
||||
assert_equal({
|
||||
title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }
|
||||
}, @post_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_including_objects_serialization_using_as_json
|
||||
PostSerializer.embed :ids, include: true
|
||||
PostSerializer._associations[:comments].send :initialize, @association.name, @association.options
|
||||
|
||||
@post_serializer.root = nil
|
||||
assert_equal({
|
||||
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
|
||||
'comments' => [{ content: 'C1' }, { content: 'C2' }]
|
||||
}, @post_serializer.as_json)
|
||||
ensure
|
||||
SETTINGS.clear
|
||||
end
|
||||
|
||||
def test_associations_using_a_given_serializer
|
||||
@association.embed_in_root = true
|
||||
@post_serializer.root = nil
|
||||
@association.serializer_class = Class.new(ActiveModel::Serializer) do
|
||||
def content
|
||||
'fake'
|
||||
end
|
||||
|
||||
attributes :content
|
||||
end
|
||||
|
||||
assert_equal({
|
||||
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
|
||||
comments: [{ content: 'fake' }, { content: 'fake' }]
|
||||
}, @post_serializer.as_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
125
test/unit/active_model/serializer/has_one_test.rb
Normal file
125
test/unit/active_model/serializer/has_one_test.rb
Normal file
@ -0,0 +1,125 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class HasOneTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@association = UserSerializer._associations[:profile]
|
||||
@old_association = @association.dup
|
||||
@association.embed = :ids
|
||||
@user = User.new({ name: 'Name 1', email: 'mail@server.com', gender: 'M' })
|
||||
@user_serializer = UserSerializer.new(@user)
|
||||
end
|
||||
|
||||
def teardown
|
||||
UserSerializer._associations[:profile] = @old_association
|
||||
end
|
||||
|
||||
def test_associations_definition
|
||||
assert_equal 1, UserSerializer._associations.length
|
||||
assert_kind_of Association::HasOne, @association
|
||||
assert_equal 'profile', @association.name
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_serialization_using_serializable_hash
|
||||
assert_equal({
|
||||
name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id
|
||||
}, @user_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_serialization_using_as_json
|
||||
assert_equal({
|
||||
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id }
|
||||
}, @user_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options
|
||||
@association.key = 'key'
|
||||
assert_equal({
|
||||
name: 'Name 1', email: 'mail@server.com', 'key' => @user.profile.object_id
|
||||
}, @user_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_objects_serialization_using_serializable_hash
|
||||
@association.embed = :objects
|
||||
assert_equal({
|
||||
name: 'Name 1', email: 'mail@server.com', profile: { name: 'N1', description: 'D1' }
|
||||
}, @user_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_objects_serialization_using_as_json
|
||||
@association.embed = :objects
|
||||
assert_equal({
|
||||
'user' => { name: 'Name 1', email: 'mail@server.com', profile: { name: 'N1', description: 'D1' } }
|
||||
}, @user_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_embedding_nil_ids_serialization_using_as_json
|
||||
@user.instance_eval do
|
||||
def profile
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal({
|
||||
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => nil }
|
||||
}, @user_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_embedding_nil_objects_serialization_using_as_json
|
||||
@association.embed = :objects
|
||||
@user.instance_eval do
|
||||
def profile
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal({
|
||||
'user' => { name: 'Name 1', email: 'mail@server.com', profile: nil }
|
||||
}, @user_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options
|
||||
@association.embed = :objects
|
||||
@association.embedded_key = 'root'
|
||||
assert_equal({
|
||||
name: 'Name 1', email: 'mail@server.com', 'root' => { name: 'N1', description: 'D1' }
|
||||
}, @user_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash
|
||||
@association.embed_in_root = true
|
||||
@user_serializer.root = nil
|
||||
assert_equal({
|
||||
name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id
|
||||
}, @user_serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_associations_embedding_ids_including_objects_serialization_using_as_json
|
||||
@association.embed_in_root = true
|
||||
@user_serializer.root = nil
|
||||
assert_equal({
|
||||
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id },
|
||||
profile: { name: 'N1', description: 'D1' }
|
||||
}, @user_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_associations_using_a_given_serializer
|
||||
@association.embed_in_root = true
|
||||
@user_serializer.root = nil
|
||||
@association.serializer_class = Class.new(ActiveModel::Serializer) do
|
||||
def name
|
||||
'fake'
|
||||
end
|
||||
|
||||
attributes :name
|
||||
end
|
||||
|
||||
assert_equal({
|
||||
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id },
|
||||
profile: { name: 'fake' }
|
||||
}, @user_serializer.as_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
39
test/unit/active_model/serializer/meta_test.rb
Normal file
39
test/unit/active_model/serializer/meta_test.rb
Normal file
@ -0,0 +1,39 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class MetaTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
end
|
||||
|
||||
def test_meta
|
||||
profile_serializer = ProfileSerializer.new(@profile, root: 'profile', meta: { total: 10 })
|
||||
|
||||
assert_equal({
|
||||
'profile' => {
|
||||
name: 'Name 1',
|
||||
description: 'Description 1'
|
||||
},
|
||||
meta: {
|
||||
total: 10
|
||||
}
|
||||
}, profile_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_meta_using_meta_key
|
||||
profile_serializer = ProfileSerializer.new(@profile, root: 'profile', meta_key: :my_meta, my_meta: { total: 10 })
|
||||
|
||||
assert_equal({
|
||||
'profile' => {
|
||||
name: 'Name 1',
|
||||
description: 'Description 1'
|
||||
},
|
||||
my_meta: {
|
||||
total: 10
|
||||
}
|
||||
}, profile_serializer.as_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
103
test/unit/active_model/serializer/root_test.rb
Normal file
103
test/unit/active_model/serializer/root_test.rb
Normal file
@ -0,0 +1,103 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class RootAsOptionTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@old_root = ProfileSerializer._root
|
||||
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@serializer = ProfileSerializer.new(@profile, root: :initialize)
|
||||
ProfileSerializer._root = true
|
||||
end
|
||||
|
||||
def teardown
|
||||
ProfileSerializer._root = @old_root
|
||||
end
|
||||
|
||||
def test_root_is_not_displayed_using_serializable_hash
|
||||
assert_equal({
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}, @serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_root_using_as_json
|
||||
assert_equal({
|
||||
initialize: {
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_root_from_serializer_name
|
||||
@serializer = ProfileSerializer.new(@profile)
|
||||
|
||||
assert_equal({
|
||||
'profile' => {
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_root_as_argument_takes_precedence
|
||||
assert_equal({
|
||||
argument: {
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}
|
||||
}, @serializer.as_json(root: :argument))
|
||||
end
|
||||
|
||||
def test_using_false_root_in_initializer_takes_precedence
|
||||
ProfileSerializer._root = 'root'
|
||||
@serializer = ProfileSerializer.new(@profile, root: false)
|
||||
|
||||
assert_equal({
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
class RootInSerializerTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@old_root = ProfileSerializer._root
|
||||
ProfileSerializer._root = :in_serializer
|
||||
profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@serializer = ProfileSerializer.new(profile)
|
||||
@rooted_serializer = ProfileSerializer.new(profile, root: :initialize)
|
||||
end
|
||||
|
||||
def teardown
|
||||
ProfileSerializer._root = @old_root
|
||||
end
|
||||
|
||||
def test_root_is_not_displayed_using_serializable_hash
|
||||
assert_equal({
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}, @serializer.serializable_hash)
|
||||
end
|
||||
|
||||
def test_root_using_as_json
|
||||
assert_equal({
|
||||
in_serializer: {
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_root_in_initializer_takes_precedence
|
||||
assert_equal({
|
||||
initialize: {
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}
|
||||
}, @rooted_serializer.as_json)
|
||||
end
|
||||
|
||||
def test_root_as_argument_takes_precedence
|
||||
assert_equal({
|
||||
argument: {
|
||||
name: 'Name 1', description: 'Description 1'
|
||||
}
|
||||
}, @rooted_serializer.as_json(root: :argument))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
21
test/unit/active_model/serializer/scope_test.rb
Normal file
21
test/unit/active_model/serializer/scope_test.rb
Normal file
@ -0,0 +1,21 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class ScopeTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@serializer = ProfileSerializer.new(nil, scope: current_user)
|
||||
end
|
||||
|
||||
def test_scope
|
||||
assert_equal('user', @serializer.scope)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
'user'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
49
test/unit/active_model/serializer/settings_test.rb
Normal file
49
test/unit/active_model/serializer/settings_test.rb
Normal file
@ -0,0 +1,49 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Settings
|
||||
class Test < ActiveModel::TestCase
|
||||
def test_settings_const_is_an_instance_of_settings
|
||||
assert_kind_of Settings, SETTINGS
|
||||
end
|
||||
|
||||
def test_settings_instance
|
||||
settings = Settings.new
|
||||
settings[:setting1] = 'value1'
|
||||
|
||||
assert_equal 'value1', settings[:setting1]
|
||||
end
|
||||
|
||||
def test_each_settings
|
||||
settings = Settings.new
|
||||
settings['setting1'] = 'value1'
|
||||
settings['setting2'] = 'value2'
|
||||
|
||||
actual = {}
|
||||
|
||||
settings.each do |k, v|
|
||||
actual[k] = v
|
||||
end
|
||||
|
||||
assert_equal({ 'setting1' => 'value1', 'setting2' => 'value2' }, actual)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
class SetupTest < ActiveModel::TestCase
|
||||
def test_setup
|
||||
ActiveModel::Serializer.setup do |settings|
|
||||
settings[:a] = 'v1'
|
||||
settings[:b] = 'v2'
|
||||
end
|
||||
|
||||
assert_equal 'v1', SETTINGS[:a]
|
||||
assert_equal 'v2', SETTINGS[:b]
|
||||
ensure
|
||||
SETTINGS.clear
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user