Compare commits

...

115 Commits

Author SHA1 Message Date
Benjamin Fleischer
bc4805cbc1 Bump version to v0.10.8 2018-11-01 16:24:08 -05:00
Benjamin Fleischer
f1a2ec7f99 Add change to changelog 2018-11-01 16:19:43 -05:00
Benjamin Fleischer
09264da273 Merge branch 'fix_thread_safety_bug' into 0-10-stable 2018-11-01 16:17:02 -05:00
Benjamin Fleischer
238d7921ec Lint per rubocop 2018-11-01 14:51:18 -05:00
Benjamin Fleischer
b358271ef5 Note that we dup the entire reflection instance 2018-11-01 14:21:59 -05:00
LongCB
c7e847fc72 Fix thread unsafe behavior 2018-11-01 14:20:47 -05:00
Benjamin Fleischer
127b04ba33 Add failing test for reflection thread safety bug 2018-11-01 13:57:07 -05:00
Benjamin Fleischer
cb67434b46
Merge pull request #2279 from mkon/link-conditions
Support conditions in link statements
2018-10-31 13:27:28 -05:00
Konstantin Munteanu
572f11b7e0 value is always a link 2018-10-25 09:54:36 +02:00
Konstantin Munteanu
ca6c009273 typos 2018-10-25 09:45:34 +02:00
Konstantin Munteanu
0d3999c36d Support conditions in link statements 2018-10-25 09:45:34 +02:00
Benjamin Fleischer
05e5ba6939
Merge pull request #2281 from alvincrespo/alvincrespo-patch-1
Fix documentation around class name comparison
2018-10-24 17:05:19 -05:00
Benjamin Fleischer
4b2b9ef730
Merge pull request #2297 from vnbrs/patch-1
Remove unnecessary line break from exception message
2018-10-24 17:02:19 -05:00
Benjamin Fleischer
01ecc5dea3 Update Changelog 2018-10-24 17:01:25 -05:00
Benjamin Fleischer
12724807e9 Merge branch 'Hirurg103-0-10-stable' into 0-10-stable 2018-10-24 16:59:59 -05:00
Vinicius Brasil
bcf21ea0a6
Remove unnecessary line break from exception message
This removes the unnecessary line break from the exception message. Example:

```
Cannot infer root key from collection type. Please\n
specify the root or each_serializer option, or render a JSON String
```
2018-10-24 14:10:59 -03:00
Dzmitry
db4e5267fd Fix the bug that serializer could not be found if the association's serializer is namespaced but the model is not
[fix #2295]
2018-10-20 15:42:11 +03:00
Benjamin Fleischer
eb865c276d Update Changelog 2018-10-11 15:03:44 -05:00
Benjamin Fleischer
506636abfb Merge branch 'f-mer-0-10-stable-eager_load' into 0-10-stable 2018-10-11 15:01:41 -05:00
Fabian Mersch
65313b901b Remove obsolete autoloads 2018-10-11 21:32:12 +02:00
Fabian Mersch
2a8b9f4105 Eager load modules on boot
Using ActiveModelSerializers with a threaded web server eg. Puma
uninitialized constant errors are thrown. Leaving this article for
reference:
http://blog.plataformatec.com.br/2012/08/eager-loading-for-greater-good/.
2018-10-11 21:32:12 +02:00
Benjamin Fleischer
fce8be0dc0
Merge pull request #2290 from rails-api/minitest_ci
Minitest 5.11 breaks; needs something like ::Minitest::Result.from
2018-10-10 10:59:37 -05:00
Benjamin Fleischer
f5f5d4db9e Fix Rails master 2018-10-10 09:39:48 -05:00
Benjamin Fleischer
ed97e94e71 Exclude deprecated rubies 2018-10-09 15:14:40 -05:00
Benjamin Fleischer
4f9d64096b Minitest 5.11 breaks; needs something like ::Minitest::Result.from 2018-10-09 14:39:41 -05:00
Alvin Crespo
3a200d7fe1
Minor doc update
Use model.class.name to do the correct comparison
2018-09-07 14:28:21 -04:00
Benjamin Fleischer
f3a19bd515
Merge pull request #2260 from abhaynikam/2258-fix-class-name-documentation
[docs] Fix class name documentation
2018-06-22 16:51:55 -05:00
Benjamin Fleischer
9c77bb6a60
Merge pull request #2263 from vthomas2007/fix-readme-lint-links
Fix Lint links in README
2018-06-22 16:50:53 -05:00
Vince Thomas
76936e7bb9 Fix Lint links in README 2018-06-21 09:46:23 -04:00
Abhay Nikam
4559774d60 Updated the defination for the class_name in documentation 2018-06-21 08:49:33 +05:30
Abhay Nikam
993a48fdcf wordsmitting 2018-06-07 10:05:21 +05:30
Abhay Nikam
65cf4836c8 Updated class_name defination. 2018-06-07 10:04:03 +05:30
Abhay Nikam
f3b202746b Added examples to use class_name options for association. 2018-06-07 09:58:48 +05:30
Benjamin Fleischer
41f2e11c4d
Merge pull request #2222 from rails-api/ci_fix
CI looks like JRuby is still failing sometimes
2017-11-19 16:21:26 -06:00
Benjamin Fleischer
5fe473fe0d JRuby AR adapter are now 5x.0 for Rails 5.x+ 2017-11-19 15:34:13 -06:00
Benjamin Fleischer
d274295ee5 Merge branch 'quake-collection_cache' into 0-10-stable 2017-11-19 11:50:41 -06:00
quake wang
a9ea81a831 resolve collection cache error 2017-11-19 11:33:48 -06:00
Benjamin Fleischer
ca531789c3 Bump to 0.10.7; update changelog 2017-11-14 20:50:51 -06:00
Benjamin Fleischer
c41e243ed8
Merge pull request #2218 from rails-api/opt_in_belongs_to_uses_foreign_key
Fix 0.10.6 regression; make using belongs_to on self opt-in
2017-11-13 09:40:37 -06:00
Benjamin Fleischer
b41451c9bf Make tests pass 2017-11-13 08:36:23 -06:00
Benjamin Fleischer
3dd6cccb4d Fix 0.10.6 regression; make using belongs_to on self opt-in 2017-11-13 08:36:23 -06:00
Benjamin Fleischer
00a47d3da4
Prove CI broken (#2220)
* Remove appveyor rubygems/bundler stuff
* Try specifying different jdbc adapter
* Attempt to fix failing JRuby test I cannot reproduce

```
bundle exec rake ci
Picked up _JAVA_OPTIONS: -Xmx2048m -Xms512m
/home/travis/.rvm/rubies/jruby-9.1.9.0/bin/jruby -w -I"lib:lib:test" -r./test/test_helper.rb  -w -I"/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/rake-11.3.0/lib" "/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/rake-11.3.0/lib/rake/rake_test_loader.rb" "test/**/*_test.rb"

ActiveModelSerializers::Adapter::JsonApi::PaginationLinksTest#test_raises_descriptive_error_when_serialization_context_unset [/home/travis/build/rails-api/active_model_serializers/test/adapter/json_api/pagination_links_test.rb:186]:
[] exception expected, not
Class: <ActiveModelSerializers::Adapter::JsonApi::PaginationLinks::MissingSerializationContextError>
Message: <" JsonApi::PaginationLinks requires a ActiveModelSerializers::SerializationContext.\n Please pass a ':serialization_context' option or\n override CollectionSerializer#paginated? to return 'false'.\n">
---Backtrace---
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/adapter/json_api/pagination_links.rb:14:in `block in initialize'
org/jruby/RubyHash.java:1187:in `fetch'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/adapter/json_api/pagination_links.rb:13:in `initialize'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/adapter/json_api.rb:520:in `pagination_links_for'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/adapter/json_api.rb:147:in `success_document'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/adapter/json_api.rb:59:in `serializable_hash'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/adapter/base.rb:59:in `as_json'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/serializable_resource.rb:8:in `as_json'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:69:in `block in as_json'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:117:in `call'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:555:in `block in compile'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:505:in `call'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:498:in `block in around'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:343:in `block in simple'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:22:in `block in instrument_rendering'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:79:in `block in notify_render'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/notifications.rb:164:in `block in instrument'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/notifications.rb:164:in `instrument'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:78:in `notify_render'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:21:in `block in instrument_rendering'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:97:in `tag_logger'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:20:in `block in instrument_rendering'
org/jruby/RubyBasicObject.java:1724:in `instance_exec'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:441:in `block in make_lambda'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:342:in `block in simple'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:497:in `block in around'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:505:in `call'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:92:in `__run_callbacks__'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:778:in `_run_render_callbacks'
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:81:in `run_callbacks'
/home/travis/build/rails-api/active_model_serializers/lib/active_model_serializers/logging.rb:68:in `block in as_json'
/home/travis/build/rails-api/active_model_serializers/test/adapter/json_api/pagination_links_test.rb:187:in `block in test_raises_descriptive_error_when_serialization_context_unset'

Command failed with status (1): [ruby -w -I"lib:lib:test" -r./test/test_helper.rb  -w -I"/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/rake-11.3.0/lib" "/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/rake-11.3.0/lib/rake/rake_test_loader.rb" "test/**/*_test.rb" ]
/home/travis/build/rails-api/active_model_serializers/vendor/bundle/jruby/2.3.0/gems/rake-11.3.0/exe/rake:27:in `<main>'
Tasks: TOP => ci => default => test
(See full trace by running task with --trace)
```
2017-11-13 08:34:56 -06:00
Benjamin Fleischer
3c5e11bb0f
Merge pull request #2216 from rails-api/serialize_resource_with_nil_id
Fix: Serialize resource type for unpersisted records (blank id)
2017-11-01 10:36:22 -05:00
Benjamin Fleischer
33ec26fa12 Merge branch 'stratigos-patch-1' into 0-10-stable 2017-10-31 16:46:20 -05:00
Todd Morningstar
0bbeeb384e Update serializers.md
* Add note that any controller reference is acceptable for `serialization_scope`
 * Add note about `ActionController::API` and `view_context` set to `nil`, with respect to accessing helpers in a Serializer
 * refs #2144
 * Update CHANGELOG.md
2017-10-31 17:15:43 -04:00
Benjamin Fleischer
196216b250
Merge pull request #2212 from rails-api/remove_legacy_embeds
Remove legacy has_many_embed_ids test [ci skip]
2017-10-31 14:54:02 -05:00
Benjamin Fleischer
51f2643f40 Style 2017-10-31 14:48:27 -05:00
Benjamin Fleischer
9745a2f735 Fix: ResourceIdentifier.for_type_with_id can serialize unpersisted resources 2017-10-31 14:47:55 -05:00
Benjamin Fleischer
5916014b48 Fix: resource object identifier with nil id excludes id 2017-10-31 14:34:30 -05:00
Benjamin Fleischer
92dde58f5f Assert serializer-defined types are not inflected 2017-10-31 14:31:33 -05:00
Benjamin Fleischer
82e90091fd Put the similar jsonapi type tests together 2017-10-31 14:29:09 -05:00
Benjamin Fleischer
b439fe69c6 Refactor jsonapi type/id tests to be more explicit 2017-10-31 14:26:05 -05:00
Benjamin Fleischer
e3480345e3
Merge pull request #2211 from rails-api/polymorphic_relationships_require_serializer_instance
JSON:API relationship tests no longer show v0.10.5 regression
2017-10-31 13:49:18 -05:00
Benjamin Fleischer
54d40c79e8
Merge pull request #2214 from jmeredith16/undeterminable-json-root
Fail if collection type cannot be inferred with json adapter (#2210)
2017-10-30 16:11:08 -05:00
Joe Meredith
c6a14c9eac Fail if collection type cannot be inferred with json adapter (#2210) 2017-10-30 13:37:37 -04:00
Benjamin Fleischer
1fd324947f Remove legacy has_many_embed_ids test 2017-10-29 22:50:59 -05:00
Benjamin Fleischer
a0de45a4d8 Fix JSON:API: for_type_and_id should always inflect_type
Should Serializer._type ever be inflected?
Right now, it won't be, but association.serializer._type will be inflected.

That's the current behavior.
2017-10-29 21:23:48 -05:00
Benjamin Fleischer
cf29db34c6 Fix JSON:API polymorphic type regression from v0.10.5 2017-10-29 20:15:15 -05:00
Benjamin Fleischer
0fcb8a6cce Fix polymorphic belongs_to tests; passes on v0.10.5 2017-10-29 19:26:14 -05:00
Benjamin Fleischer
5e1e138d47 Refactor ResourceIdentifier 2017-10-29 17:13:34 -05:00
Vedant Agarwala
4076a480b7 Removed misleading line in README
As mentioned in the `master` branch's README, master will not be release ready for now.
Fixes https://github.com/rails-api/active_model_serializers/issues/2163
2017-10-29 16:26:32 -05:00
Nate Pinsky
88367da970 Add warnings about global adapter config to docs (#2176) 2017-10-24 17:30:56 -05:00
Dennis Stumm
4d7c2457d7 Fix deserialization of polymorphic relationships (#2200)
* Classify the relationship type for polymorphic associations
2017-10-07 17:03:38 -05:00
Benjamin Fleischer
715a702f55 Merge pull request #2189 from tagliala/update-jsonapi-renderer-dependency
Update version constraint for jsonapi-renderer
2017-09-19 15:32:44 -05:00
Benjamin Fleischer
4a995955ea Merge pull request #2198 from tagliala/improve-travis-configuration
Test against latest stable Ruby and Rails versions
2017-09-19 15:31:57 -05:00
Geremia Taglialatela
ab517d1a2d Test against latest stable Ruby and Rails versions
Also skips Rails 4.1 tests against Ruby 2.4.2 and ruby-head,
because Rails 4.2.8 is the first version of the 4.x series that
officially	support Ruby 2.4.
2017-09-19 17:47:52 +02:00
Geremia Taglialatela
1c9214d041
Update version constraint for jsonapi-renderer 2017-09-19 16:57:09 +02:00
Benjamin Fleischer
6a7d864605 Fix CI on 0-10-stable (#2181)
* Loosen pry, pry-byebug depencency

```
Resolving dependencies...
byebug-9.1.0 requires ruby version >= 2.2.0, which is
incompatible with the current version, ruby 2.1.10p492
```

* Adjust nokogiri version constraint for CI

Update appveyor Ruby to 2.3 to work around:

```
Gem::InstallError: nokogiri requires Ruby version < 2.5, >= 2.2.

An error occurred while installing nokogiri (1.8.0), and Bundler cannot continue.
Make sure that `gem install nokogiri -v '1.8.0'` succeeds before bundling.
```

and not 2.4 since:

https://ci.appveyor.com/project/bf4/active-model-serializers/build/1.0.1052-fix_ci/job/0q3itabsnvnxr83u

```
nokogiri-1.6.8.1-x86-mingw32 requires ruby version < 2.4, which is incompatible with the current version, ruby 2.4.1p111
```

* Include rails gem in Gemfile

(For Rails5)

In Rails5, checking for Rails::Railtie is better

* Rails5 test env requires Rails.application.class.name

rails-42d09f6b49da/railties/lib/rails/application.rb

```ruby
def secret_key_base
  if Rails.env.test? || Rails.env.development?
  Digest::MD5.hexdigest self.class.name
```

* Reformat exclude matrix to be easier to read

* Simplify jruby-travis config per rails/rails

* Organize .travis.yml per rails/rails

* Allow JRuby failure on Rails 5+; try rails-5 db adapter branch

https://github.com/jruby/activerecord-jdbc-adapter/issues/708

```
uninitialized constant ActiveRecord::ConnectionAdapters::Column::Format
```

see https://travis-ci.org/rails-api/active_model_serializers/jobs/277112008
2017-09-19 05:27:02 -04:00
Benjamin Fleischer
c2fa01624d Merge pull request #2191 from tagliala/fix-rubocop-offence
Fix RuboCop offence
2017-09-17 12:59:12 -05:00
Geremia Taglialatela
4f78319219 Fix RuboCop offence 2017-09-17 19:33:05 +02:00
Benjamin Fleischer
b1de431731 Merge pull request #2179 from drn/enumerator-exception
Fix Enumerator.new ArgumentError.
2017-08-29 10:14:25 -05:00
Darren Cheng
967ff8dcc0 Patch Enumerator.new ArgumentError. 2017-08-28 19:38:08 -07:00
Alexandre de Oliveira
1e4d117b99 Merge pull request #2149 from mecampbellsoup/more-pagination-links-by-default
Always include self, first, last pagination links
2017-06-14 15:47:30 -03:00
mecampbellsoup
402883d84f Fix Travis lint offenses 2017-06-14 13:35:00 -04:00
mecampbellsoup
e4b3224c64 Fix indentation mismatch 2017-06-14 12:53:38 -04:00
mecampbellsoup
b7442e741c Use symbolized keys for json hash
They will be converted to strings when rendered as JSON.
2017-06-14 12:52:29 -04:00
Benjamin Fleischer
1539747a59 Merge pull request #2152 from tannerj/0-10-stable
Fix dead link in docs/general/rendering
2017-06-13 20:08:29 -05:00
Joel Tanner Jones
622872ae2b Fix dead link in docs/general/rendering
The add_pageination_links.md is dead in docs/general/rendering on the
0-10-stable branch.
2017-06-13 13:28:24 -04:00
mecampbellsoup
92e9a66e97 Amend tests to always include all pagination keys 2017-06-13 12:35:55 -04:00
mecampbellsoup
16e5204eab Always include pagination keys but set null values when not needed 2017-06-13 12:09:00 -04:00
mecampbellsoup
ff71ef26eb Amend pagination controller specs 2017-06-05 18:41:15 -04:00
mecampbellsoup
d8e983604b Clarify naming of expected response w/ pagination but empty data 2017-06-05 17:51:38 -04:00
mecampbellsoup
7387266c37 Always display self, first, last pagination links 2017-06-05 17:26:41 -04:00
Christian
a89e78c655 Allow referencing sideloaded include by key. (#2136)
* If a `key` is set on the reflection use the `key` instead of `name`.
This ensures that associations with a key set are still included.
2017-05-18 15:59:14 -05:00
Benjamin Fleischer
a5ab62fd18 Merge pull request #2130 from greysteil/allow-id-overwriting
Allow serialized ID to be overwritten for belongs-to relationships
2017-05-15 09:24:41 -05:00
Grey Baker
be7ee70376 Allow serialized ID to be overwritten for belongs-to relationships
If the `id` attribute for a class isn't taken directly from the object when
serializing it, it may be desirible for other classes that serialize a
relationship with that class to overwrite the relationship IDs they serialize.

For example, suppose we have:

```(ruby)
class Repo < Model
  attributes :id, :github_id, :name
  associations :configs
end

class Config < Model
  attributes :id
  belongs_to :repo
end

class RepoSerializer < ActiveModel::Serializer
  attributes :id, :name

  has_many :update_configs

  def id
    object.github_id
  end
end

class ConfigSerializer < ActiveModel::Serializer
  attributes :id
  belongs_to :repo
end
```

In the above example, serializing a list of `Repo`s will give the `github_id`
for each one, but serializing a `Config` will give the `id` for its parent repo.

Ideally AMS would inspect the `RepoSerializer` when serializing the `Config`,
and realise it can't just output the foreign key. Unfortunately, getting the
serialization class for the child repo currently requires loading the record
(via evaluating `lazy_assocation`), and loses the performance benefit of the
existing `belongs_to?` path. Instead, I've opted to use
`read_attribute_for_serialization` instead of `object.send` to fetch the
serialized foreign key. This allows the serialized relationship ID to be
overwritten using

```(ruby)
class ConfigSerializer < ActiveModel::Serializer
  ...

  def repo_id
    object.repo.github_id
  end
end
```
2017-05-13 15:22:18 +01:00
Benjamin Fleischer
b48aeeef1e Merge branch 'master' into 0-10-stable 2017-05-01 11:04:46 -05:00
Benjamin Fleischer
01d4f0464b Merge branch 'master' into 0-10-stable 2017-03-07 15:52:27 -06:00
Benjamin Fleischer
f353dedf28 Merge pull request #2038 from nsarno/patch-1
Fix small typo in README.md
2017-01-31 09:05:59 -06:00
Arnaud Mesureur
db617b8bf9 Fix small typo in README.md 2017-01-23 15:42:03 +11:00
Benjamin Fleischer
9a2f4894ed Merge pull request #1981 from groyoh/link_doc
Fix relationship links doc
Conflicts:
	CHANGELOG.md
2017-01-10 01:07:18 -06:00
Benjamin Fleischer
4c6f104ae9 Merge pull request #2022 from bf4/fix_model_attribute_accessors
Fix model attribute accessors
2017-01-10 01:05:27 -06:00
Benjamin Fleischer
1570437795 Add CHANGELOG 2017-01-10 00:41:09 -06:00
Benjamin Fleischer
ec1022ecb3 Test bugfix 2017-01-10 00:41:09 -06:00
Benjamin Fleischer
b5f886cb95 Randomize testing of compatibility layer against regressions 2017-01-10 00:41:09 -06:00
Benjamin Fleischer
ec905d8179 Fix typos 2017-01-10 00:41:08 -06:00
Benjamin Fleischer
c25f2f3863 Fix model attributes accessors 2017-01-10 00:41:08 -06:00
Benjamin Fleischer
4e6bd61350 Merge pull request #2021 from bf4/make_tests_explicit
Add Model#attributes helper; make test attributes explicit
2017-01-08 16:37:53 -05:00
Benjamin Fleischer
d5babdd060 Add Model#attributes helper; make test attributes explicit 2017-01-07 21:50:11 -06:00
Benjamin Fleischer
85dfef9072 Merge pull request #2012 from bf4/cleanup_isolated_jsonapi_renderer_tests_a_bit
Cleanup assertions in isolated jsonapi renderer tests a bit
2017-01-07 16:31:45 -06:00
Ankit Shah
59aed4d00e Updated isolated tests to assert correct behavior. (#2010)
* Updated isolated tests to assert correct behavior.
* Added check to get unsafe params if rails version is great than 5
2017-01-07 16:27:57 -06:00
Benjamin Fleischer
a5423dab20 Merge pull request #2017 from bf4/remove_warnings
Fix mt6 assert_nil warnings
2017-01-07 16:26:34 -06:00
Benjamin Fleischer
9a2e1e4743 Merge pull request #2020 from bf4/silence_grape_warnings
Silence Grape warnings
2017-01-07 16:26:24 -06:00
Benjamin Fleischer
0dd7680fe5 Merge pull request #2019 from bf4/fix_method_redefined_warning
Fix AMS warnings
2017-01-07 16:26:18 -06:00
Benjamin Fleischer
21bcfd891d Merge pull request #2018 from rails-api/bump_version
Bump to v0.10.4 [ci skip]
Conflicts:
	CHANGELOG.md
2017-01-07 16:25:50 -06:00
Benjamin Fleischer
82db1301f6 Bump to v0.10.4 2017-01-06 16:21:04 -06:00
Benjamin Fleischer
23f03ffd30 Merge pull request #2016 from rails-api/prepare_release
Prepare release of 0.10.4
2017-01-06 17:14:08 -05:00
Benjamin Fleischer
97b587b14c Merge pull request #2005 from kofronpi/support-ruby-2.4
Update jsonapi runtime dependency to 0.1.1.beta6
2017-01-06 14:17:37 -06:00
L. Preston Sego III
adf110f4df Swap out KeyTransform for CaseTransform (#1993)
* delete KeyTransform, use CaseTransform

* added changelog

Conflicts:
	CHANGELOG.md
2017-01-06 14:17:37 -06:00
Benjamin Fleischer
2c0b15d22f Merge pull request #2007 from bf4/check_ci
Test was failing due to change in JSON exception message when parsing empty string
2017-01-06 14:17:35 -06:00
Benjamin Fleischer
dfa6caac27 Merge pull request #2000 from berfarah/patch-1
Link to 0.10.3 tag instead of `master` branch
2017-01-05 21:36:32 -06:00
Benjamin Fleischer
49f2dca730 Merge pull request #1999 from bf4/typos
Fix typos [ci skip]
2017-01-05 21:36:25 -06:00
Benjamin Fleischer
4054f43309 Merge pull request #1994 from bf4/promote_architecture
Promote important architecture description that answers a lot of questions we get
Conflicts:
	docs/ARCHITECTURE.md
2017-01-05 21:35:57 -06:00
L. Preston Sego III
e036b71e0c Merge pull request #1992 from ojiry/bump_ruby_versions
Run tests by Ruby 2.2.6 and 2.3.3
2017-01-05 21:33:07 -06:00
Benjamin Fleischer
6e11d6234e Merge pull request #1990 from mxie/mx-result-typo
Fix typos and capitalization in Relationship Links docs [ci skip]
2017-01-05 21:32:31 -06:00
42 changed files with 826 additions and 369 deletions

View File

@ -1,55 +1,54 @@
language: ruby
sudo: false
rvm:
- 2.1
- 2.2.6
- 2.3.3
- ruby-head
- jruby-9.1.5.0 # is precompiled per http://rubies.travis-ci.org/
- jruby-head
jdk:
- oraclejdk8
before_install:
- gem update --system
- rvm @global do gem uninstall bundler -a -x
- rvm @global do gem install bundler -v 1.13.7
install: bundle install --path=vendor/bundle --retry=3 --jobs=3
cache:
directories:
- vendor/bundle
before_install:
- "travis_retry gem update --system"
- "travis_retry gem update bundler"
install: bundle install --path=vendor/bundle --retry=3 --jobs=3
script:
- bundle exec rake ci
after_success:
- codeclimate-test-reporter
env:
global:
- "JRUBY_OPTS='--dev -J-Xmx1024M --debug'"
matrix:
- "RAILS_VERSION=4.1"
- "RAILS_VERSION=4.2"
- "RAILS_VERSION=5.0"
- "RAILS_VERSION=5.1"
- "RAILS_VERSION=master"
rvm:
- 2.1.10
- 2.2.8
- 2.3.5
- 2.4.2
- ruby-head
matrix:
include:
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=4.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=4.2 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=5.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
# See JRuby currently failing on Rails 5+ https://github.com/jruby/activerecord-jdbc-adapter/issues/708
# - { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=5.0 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
# - { rvm: jruby-head, jdk: oraclejdk8, env: "RAILS_VERSION=5.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
exclude:
- rvm: 2.1
env: RAILS_VERSION=master
- rvm: jruby-9.1.5.0
env: RAILS_VERSION=master
- rvm: jruby-head
env: RAILS_VERSION=master
- rvm: 2.1
env: RAILS_VERSION=5.0
- rvm: jruby-9.1.5.0
env: RAILS_VERSION=5.0
- rvm: jruby-head
env: RAILS_VERSION=5.0
- { rvm: 2.1.10, env: RAILS_VERSION=master }
- { rvm: 2.2.8, env: RAILS_VERSION=master }
- { rvm: 2.3.5, env: RAILS_VERSION=master }
- { rvm: 2.1.10, env: RAILS_VERSION=5.0 }
- { rvm: 2.1.10, env: RAILS_VERSION=5.1 }
- { rvm: 2.4.2, env: RAILS_VERSION=4.1 }
- { rvm: ruby-head, env: RAILS_VERSION=4.1 }
allow_failures:
- rvm: ruby-head
- rvm: jruby-head
# See JRuby currently failing on Rails 5+ https://github.com/jruby/activerecord-jdbc-adapter/issues/708
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=5.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
fast_finish: true

View File

@ -1,6 +1,6 @@
## 0.10.x
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.6...master)
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.8...0-10-stable)
Breaking changes:
@ -8,8 +8,69 @@ Features:
Fixes:
Misc:
### [v0.10.8 (2018-11-01)](https://github.com/rails-api/active_model_serializers/compare/v0.10.7...v0.10.8)
Features:
- [#2279](https://github.com/rails-api/active_model_serializers/pull/2279) Support condition options in serializer link statements
Fixes:
- [#2296](https://github.com/rails-api/active_model_serializers/pull/2296) Fixes #2295 (@Hirurg103)
- Fix finding of namespaced serializer and non-namespaced model.
- [#2289](https://github.com/rails-api/active_model_serializers/pull/2289) Fixes #2255 (@f-mer)
- Fix autoloading race condition, especially in Rails 5.
- [#2299](https://github.com/rails-api/active_model_serializers/pull/2299) Fixes #2270 (@chau-bao-long via #2276)
- Fix reflection thread-safety bug
### [v0.10.7 (2017-11-14)](https://github.com/rails-api/active_model_serializers/compare/v0.10.6...v0.10.7)
Regressions Fixed From v0.10.6:
- [#2211](https://github.com/rails-api/active_model_serializers/pull/2211). Fixes #2125, #2160. (@bf4)
- Fix polymorphic belongs_to tests; passes on v0.10.5, fails on v0.10.6
- Fix JSON:API polymorphic type regression from v0.10.5
- Fix JSON:API: for_type_and_id should always inflect_type
```
Should Serializer._type ever be inflected?
Right now, it won't be, but association.serializer._type will be inflected.
That's the current behavior.
```
- [#2216](https://github.com/rails-api/active_model_serializers/pull/2216). Fixes #2132, #2180. (@bf4)
- Fix JSON:API: Serialize resource type for unpersisted records (blank id)
- [#2218](https://github.com/rails-api/active_model_serializers/pull/2218). Fixes #2178. (@bf4)
- Fix JSON:API: Make using foreign key on belongs_to opt-in. No effect on polymorphic relationships.
```
# set to true to opt-in
ActiveModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
```
Features:
- [#2136](https://github.com/rails-api/active_model_serializers/pull/2136) Enable inclusion of sideloaded relationship objects by `key`. (@caomania)
- [#2021](https://github.com/rails-api/active_model_serializers/pull/2021) ActiveModelSerializers::Model#attributes. Originally in [#1982](https://github.com/rails-api/active_model_serializers/pull/1982). (@bf4)
- [#2130](https://github.com/rails-api/active_model_serializers/pull/2130) Allow serialized ID to be overwritten for belongs-to relationships. (@greysteil)
- [#2189](https://github.com/rails-api/active_model_serializers/pull/2189)
Update version constraint for jsonapi-renderer to `['>= 0.1.1.beta1', '< 0.3']`
(@tagliala)
Fixes:
- [#2022](https://github.com/rails-api/active_model_serializers/pull/2022) Mutation of ActiveModelSerializers::Model now changes the attributes. Originally in [#1984](https://github.com/rails-api/active_model_serializers/pull/1984). (@bf4)
- [#2200](https://github.com/rails-api/active_model_serializers/pull/2200) Fix deserialization of polymorphic relationships. (@dennis95stumm)
- [#2214](https://github.com/rails-api/active_model_serializers/pull/2214) Fail if unable to infer collection type with json adapter. (@jmeredith16)
- [#2149](https://github.com/rails-api/active_model_serializers/pull/2149) Always include self, first, last pagination link. (@mecampbellsoup)
- [#2179](https://github.com/rails-api/active_model_serializers/pull/2179) Fixes #2173, Pass block to Enumerator.new. (@drn)
Misc:
- [#2176](https://github.com/rails-api/active_model_serializers/pull/2176) Documentation for global adapter config. (@mrpinsky)
- [#2215](https://github.com/rails-api/active_model_serializers/pull/2215) Update `serializers.md` documentation to denote alternate use cases for `scope`. (@stratigos)
- [#2212](https://github.com/rails-api/active_model_serializers/pull/2212) Remove legacy has_many_embed_ids test. (@bf4)
### [v0.10.6 (2017-05-01)](https://github.com/rails-api/active_model_serializers/compare/v0.10.5...v0.10.6)
Fixes:

24
Gemfile
View File

@ -12,6 +12,7 @@ version = ENV['RAILS_VERSION'] || '4.2'
if version == 'master'
gem 'rack', github: 'rack/rack'
gem 'arel', github: 'rails/arel'
gem 'rails', github: 'rails/rails'
git 'https://github.com/rails/rails.git' do
gem 'railties'
gem 'activesupport'
@ -23,6 +24,7 @@ if version == 'master'
end
else
gem_version = "~> #{version}.0"
gem 'rails', gem_version
gem 'railties', gem_version
gem 'activesupport', gem_version
gem 'activemodel', gem_version
@ -36,18 +38,32 @@ end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: (@windows_platforms + [:jruby])
if ENV['CI']
if RUBY_VERSION < '2.4'
# Windows: An error occurred while installing nokogiri (1.8.0)
gem 'nokogiri', '< 1.7', platforms: @windows_platforms
end
end
group :bench do
# https://github.com/rails-api/active_model_serializers/commit/cb4459580a6f4f37f629bf3185a5224c8624ca76
gem 'benchmark-ips', '>= 2.7.2', require: false, group: :development
end
group :test do
gem 'sqlite3', platform: (@windows_platforms + [:ruby])
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
gem 'sqlite3', platform: (@windows_platforms + [:ruby])
platforms :jruby do
if version == 'master' || version >= '5'
gem 'activerecord-jdbcsqlite3-adapter', '~> 50'
else
gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3.0'
end
end
gem 'codeclimate-test-reporter', require: false
gem 'm', '~> 1.5'
gem 'pry', '~> 0.10'
gem 'pry-byebug', '~> 3.4', platform: :ruby
gem 'pry', '>= 0.10'
gem 'byebug', '~> 8.2' if RUBY_VERSION < '2.2'
gem 'pry-byebug', platform: :ruby
end
group :development, :test do

View File

@ -49,8 +49,6 @@ Check how to change the adapter in the sections below.
`0.10.x` is based on the `0.8.0` code, but with a more flexible
architecture. We'd love your help. [Learn how you can help here.](CONTRIBUTING.md)
It is generally safe and recommended to use the master branch.
## Installation
Add this line to your application's Gemfile:
@ -187,7 +185,7 @@ and, if there is no serializer, primitives.
### ActiveModelSerializers::Adapter::Base
The **`ActiveModelSerializeres::Adapter::Base`** describes the structure of the JSON document generated from a
The **`ActiveModelSerializers::Adapter::Base`** describes the structure of the JSON document generated from a
serializer. For example, the `Attributes` example represents each serializer as its
unmodified attributes. The `JsonApi` adapter represents the serializer as a [JSON
API](http://jsonapi.org/) document.
@ -268,8 +266,8 @@ to know about, but not part of ActiveModelSerializers.)
- An `ActiveRecord::Base` object.
- Any Ruby object that passes the
[Lint](http://www.rubydoc.info/github/rails-api/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
[code](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/lint.rb).
[Lint](https://www.rubydoc.info/gems/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
[(code)](lib/active_model/serializer/lint.rb).
ActiveModelSerializers provides a
[`ActiveModelSerializers::Model`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/model.rb),

View File

@ -39,10 +39,10 @@ Gem::Specification.new do |spec|
# 'activesupport', rails_versions
# 'i18n,
# 'tzinfo'
# 'minitest'
spec.add_development_dependency 'minitest', ['~> 5.0', '< 5.11']
# 'thread_safe'
spec.add_runtime_dependency 'jsonapi-renderer', ['>= 0.1.1.beta1', '< 0.2']
spec.add_runtime_dependency 'jsonapi-renderer', ['>= 0.1.1.beta1', '< 0.3']
spec.add_runtime_dependency 'case_transform', '>= 0.2'
spec.add_development_dependency 'activerecord', rails_versions

View File

@ -5,19 +5,17 @@ skip_tags: true
environment:
JRUBY_OPTS: "--dev -J-Xmx1024M --debug"
matrix:
- ruby_version: "Ruby21"
- ruby_version: "Ruby21-x64"
- ruby_version: "Ruby23"
- ruby_version: "Ruby23-x64"
cache:
- vendor/bundle
install:
- SET PATH=C:\%ruby_version%\bin;%PATH%
- gem update --system
- gem uninstall bundler -a -x
- gem install bundler -v 1.13.7
- bundle env
- bundle install --path=vendor/bundle --retry=3 --jobs=3
- bundle check || bundle install --path=vendor/bundle --retry=3 --jobs=3
- bundle clean --force
before_test:
- ruby -v

View File

@ -36,6 +36,12 @@ The `Attributes` adapter does not include a root key. It is just the serialized
Use either the `JSON` or `JSON API` adapters if you want the response document to have a root key.
***IMPORTANT***: Adapter configuration has *no effect* on a serializer instance
being used directly. That is, `UserSerializer.new(user).as_json` will *always*
behave as if the adapter were the 'Attributes' adapter. See [Outside Controller
Usage](../howto/outside_controller_use.md) for more details on recommended
usage.
## Built in Adapters
### Attributes - Default

View File

@ -57,6 +57,7 @@ still prefer the render option `:key_transform` over this setting.
application, setting `config.key_transform` to `:unaltered` will provide a performance boost.*
##### default_includes
What relationships to serialize by default. Default: `'*'`, which includes one level of related
objects. See [includes](adapters.md#included) for more info.
@ -162,6 +163,21 @@ Default: `{}`.
*Used when `jsonapi_include_toplevel_object` is `true`*
##### jsonapi_use_foreign_key_on_belongs_to_relationship
When true, the relationship will determine its resource object identifier
without calling the association or its serializer. This can be useful when calling
the association object is triggering unnecessary queries.
For example, if a `comment` belongs to a `post`, and the comment
uses the foreign key `post_id`, we can determine the resource object
identifier `id` as `comment.post_id` and the `type` from the association options.
Or quite simply, it behaves as `belongs_to :post, type: :posts, foreign_key: :post_id`.
Note: This option has *no effect* on polymorphic associations as we cannot reliably
determine the associated object's type without instantiating it.
Default: `false`.
## Hooks

View File

@ -290,4 +290,4 @@ See [Usage outside of a controller](../howto/outside_controller_use.md#serializi
## Pagination
See [How to add pagination links](https://github.com/rails-api/active_model_serializers/blob/master/docs/howto/add_pagination_links.md).
See [How to add pagination links](../howto/add_pagination_links.md).

View File

@ -65,7 +65,7 @@ Where:
- `virtual_value:`
- `polymorphic:` defines if polymorphic relation type should be nested in serialized association.
- `type:` the resource type as used by JSON:API, especially on a `belongs_to` relationship.
- `class_name:` used to determine `type` when `type` not given
- `class_name:` the (String) model name used to determine `type`, when `type` is not given. e.g. `class_name: "Comment"` would imply the type `comments`
- `foreign_key:` used by JSON:API on a `belongs_to` relationship to avoid unnecessarily loading the association object.
- `namespace:` used when looking up the serializer and `serializer` is not given. Falls back to the parent serializer's `:namespace` instance options, which, when present, comes from the render options. See [Rendering#namespace](rendering.md#namespace] for more details.
- optional: `&block` is a context that returns the association's attributes.
@ -81,6 +81,7 @@ e.g.
```ruby
has_one :bio
has_one :blog, key: :site
has_one :blog, class_name: "Blog"
has_one :maker, virtual_value: { id: 1 }
has_one :blog do |serializer|
@ -114,6 +115,7 @@ e.g.
has_many :comments
has_many :comments, key: :reviews
has_many :comments, serializer: CommentPreviewSerializer
has_many :comments, class_name: "Comment"
has_many :reviews, virtual_value: [{ id: 1 }, { id: 2 }]
has_many :comments, key: :last_comments do
last(1)
@ -127,6 +129,7 @@ e.g.
```ruby
belongs_to :author, serializer: AuthorPreviewSerializer
belongs_to :author, key: :writer
belongs_to :author, class_name: "Author"
belongs_to :post
belongs_to :blog
def blog
@ -235,6 +238,15 @@ link :other, 'https://example.com/resource'
link(:posts) { link_author_posts_url(object) }
```
Just like attributes, links also support conditions in options
```ruby
link(:secret, if: :internal?) { object.secret_link }
def internal?
instance_options[:context] == :internal
end
```
#### #object
The object being serialized.
@ -294,6 +306,8 @@ end
Whether you write the method as above or as `object.comments.where(created_by: scope)`
is a matter of preference (assuming `scope_name` has been set).
Keep in mind that the scope can be set to any available controller reference. This can be utilized to provide access to any other data scopes or presentation helpers.
##### Controller Authorization Context
In the controller, the scope/scope_name options are equal to
@ -311,7 +325,7 @@ current authorization scope when you call `render :json`.
called on every request. This was [also a problem](https://github.com/rails-api/active_model_serializers/pull/1252#issuecomment-159810477)
in [`0.9`](https://github.com/rails-api/active_model_serializers/tree/0-9-stable#customizing-scope).
We can change the scope from `current_user` to `view_context`.
We can change the scope from `current_user` to `view_context`, which is included in subclasses of `ActionController::Base`.
```diff
class SomeController < ActionController::Base
@ -379,6 +393,7 @@ class PostsController < ActionController::Base
end
end
```
Note that any controller reference which provides the desired scope is acceptable, such as another controller method for loading a different resource or reference to helpers. For example, `ActionController::API` does not include `ActionView::ViewContext`, and would need a different reference for passing any helpers into a serializer via `serialization_scope`.
#### #read_attribute_for_serialization(key)
@ -471,7 +486,7 @@ the `ActiveModel::Serializer.serializer_for` method to return a serializer class
```ruby
class MySerializer < ActiveModel::Serializer
def self.serializer_for(model, options)
return SparseAdminSerializer if model.class == 'Admin'
return SparseAdminSerializer if model.class.name == 'Admin'
super
end

View File

@ -18,6 +18,13 @@ In order to add the root key you need to use the ```JSON``` Adapter, you can cha
ActiveModelSerializers.config.adapter = :json
```
Note that adapter configuration has no effect on a serializer that is called
directly, e.g. in a serializer unit test. Instead, something like
`UserSerializer.new(user).as_json` will *always* behave as if the adapter were
the 'Attributes' adapter. See [Outside Controller
Usage](../howto/outside_controller_use.md) for more details on recommended
usage.
You can also specify a class as adapter, as long as it complies with the ActiveModelSerializers adapters interface.
It will add the root key to all your serialized endpoints.

View File

@ -18,16 +18,17 @@ module ActiveModel
# @see #serializable_hash for more details on these valid keys.
SERIALIZABLE_HASH_VALID_KEYS = [:only, :except, :methods, :include, :root].freeze
extend ActiveSupport::Autoload
autoload :Adapter
autoload :Null
autoload :Attribute
autoload :Association
autoload :Reflection
autoload :SingularReflection
autoload :CollectionReflection
autoload :BelongsToReflection
autoload :HasOneReflection
autoload :HasManyReflection
eager_autoload do
autoload :Adapter
autoload :Null
autoload :Attribute
autoload :Link
autoload :Association
autoload :Reflection
autoload :BelongsToReflection
autoload :HasOneReflection
autoload :HasManyReflection
end
include ActiveSupport::Configurable
include Caching
@ -142,6 +143,7 @@ module ActiveModel
# Make JSON API top-level jsonapi member opt-in
# ref: http://jsonapi.org/format/#document-top-level
config.jsonapi_include_toplevel_object = false
config.jsonapi_use_foreign_key_on_belongs_to_relationship = false
config.include_data_default = true
# For configuring how serializers are found.
@ -274,9 +276,14 @@ module ActiveModel
# link(:self) { "http://example.com/resource/#{object.id}" }
# @example
# link :resource, "http://example.com/resource"
# @example
# link(:callback, if: :internal?), { "http://example.com/callback" }
#
def self.link(name, value = nil, &block)
_links[name] = block || value
def self.link(name, *args, &block)
options = args.extract_options!
# For compatibility with the use case of passing link directly as string argument
# without block, we are creating a wrapping block
_links[name] = Link.new(name, options, block || ->(_serializer) { args.first })
end
# Set the JSON API meta attribute of a serializer.
@ -337,10 +344,10 @@ module ActiveModel
# @return [Enumerator<Association>]
def associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil)
include_slice ||= include_directive
return Enumerator.new unless object
return Enumerator.new {} unless object
Enumerator.new do |y|
self.class._reflections.each do |key, reflection|
(self.instance_reflections ||= self.class._reflections.deep_dup).each do |key, reflection|
next if reflection.excluded?(self)
next unless include_directive.key?(key)
@ -404,6 +411,6 @@ module ActiveModel
protected
attr_accessor :instance_options
attr_accessor :instance_options, :instance_reflections
end
end

View File

@ -19,11 +19,10 @@ module ActiveModel
# @api private
def serializable_hash(adapter_options, options, adapter_instance)
include_directive = ActiveModel::Serializer.include_directive_from_options(adapter_options)
adapter_options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, include_directive)
adapter_opts = adapter_options.merge(include_directive: include_directive)
options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, options[:include_directive])
serializers.map do |serializer|
serializer.serializable_hash(adapter_opts, options, adapter_instance)
serializer.serializable_hash(adapter_options, options, adapter_instance)
end
end
@ -46,7 +45,9 @@ module ActiveModel
# 3. get from collection name, if a named collection
key ||= object.respond_to?(:name) ? object.name && object.name.underscore : nil
# 4. key may be nil for empty collection and no serializer option
key && key.pluralize
key &&= key.pluralize
# 5. fail if the key cannot be determined
key || fail(ArgumentError, 'Cannot infer root key from collection type. Please specify the root or each_serializer option, or render a JSON String')
end
# rubocop:enable Metrics/CyclomaticComplexity

View File

@ -76,6 +76,7 @@ module ActiveModel
serializer_options[:serializer_context_class] = association_options.fetch(:parent_serializer).class
serializer = reflection_options.fetch(:serializer, nil)
serializer_options[:serializer] = serializer if serializer
serializer_options[:namespace] = reflection_options[:namespace] if reflection_options[:namespace]
serializer_class.new(object, serializer_options)
end

View File

@ -0,0 +1,21 @@
require 'active_model/serializer/field'
module ActiveModel
class Serializer
# Holds all the data about a serializer link
#
# @example
# class PostSerializer < ActiveModel::Serializer
# link :callback, if: :internal? do
# object.callback_link
# end
#
# def internal?
# instance_options[:internal] == true
# end
# end
#
class Link < Field
end
end
end

View File

@ -140,7 +140,7 @@ module ActiveModel
def include_data?(include_slice)
include_data_setting = options[:include_data_setting]
case include_data_setting
when :if_sideloaded then include_slice.key?(name)
when :if_sideloaded then include_slice.key?(options.fetch(:key, name))
when true then true
when false then false
else fail ArgumentError, "Unknown include_data_setting '#{include_data_setting.inspect}'"
@ -151,6 +151,9 @@ module ActiveModel
# @yield [ActiveModel::Serializer]
# @return [:nil, associated resource or resource collection]
def value(serializer, include_slice)
# NOTE(BF): This method isn't thread-safe because the _reflections class attribute is not thread-safe
# Therefore, when we build associations from reflections, we dup the entire reflection instance.
# Better solutions much appreciated!
@object = serializer.object
@scope = serializer.scope

View File

@ -1,5 +1,5 @@
module ActiveModel
class Serializer
VERSION = '0.10.6'.freeze
VERSION = '0.10.8'.freeze
end
end

View File

@ -5,16 +5,19 @@ require 'active_support/core_ext/string/inflections'
require 'active_support/json'
module ActiveModelSerializers
extend ActiveSupport::Autoload
autoload :Model
autoload :Callbacks
autoload :Deserialization
autoload :SerializableResource
autoload :Logging
autoload :Test
autoload :Adapter
autoload :JsonPointer
autoload :Deprecate
autoload :LookupChain
eager_autoload do
autoload :Model
autoload :Callbacks
autoload :SerializableResource
autoload :SerializationContext
autoload :Logging
autoload :Test
autoload :Adapter
autoload :JsonPointer
autoload :Deprecate
autoload :LookupChain
autoload :Deserialization
end
class << self; attr_accessor :logger; end
self.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
@ -46,8 +49,13 @@ module ActiveModelSerializers
$VERBOSE = original_verbose
end
def self.eager_load!
super
ActiveModel::Serializer.eager_load!
end
require 'active_model/serializer/version'
require 'active_model/serializer'
require 'active_model/serializable_resource'
require 'active_model_serializers/railtie' if defined?(::Rails)
require 'active_model_serializers/railtie' if defined?(::Rails::Railtie)
end

View File

@ -22,14 +22,16 @@ module ActiveModelSerializers
module Adapter
class JsonApi < Base
extend ActiveSupport::Autoload
autoload :Jsonapi
autoload :ResourceIdentifier
autoload :Relationship
autoload :Link
autoload :PaginationLinks
autoload :Meta
autoload :Error
autoload :Deserialization
eager_autoload do
autoload :Jsonapi
autoload :ResourceIdentifier
autoload :Link
autoload :PaginationLinks
autoload :Meta
autoload :Error
autoload :Deserialization
autoload :Relationship
end
def self.default_key_transform
:dash
@ -480,7 +482,8 @@ module ActiveModelSerializers
# }.reject! {|_,v| v.nil? }
def links_for(serializer)
serializer._links.each_with_object({}) do |(name, value), hash|
result = Link.new(serializer, value).as_json
next if value.excluded?(serializer)
result = Link.new(serializer, value.block).as_json
hash[name] = result if result
end
end

View File

@ -189,7 +189,7 @@ module ActiveModelSerializers
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
if polymorphic
hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'] : nil
hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'].classify : nil
end
hash

View File

@ -15,17 +15,18 @@ module ActiveModelSerializers
JsonApi::PaginationLinks requires a ActiveModelSerializers::SerializationContext.
Please pass a ':serialization_context' option or
override CollectionSerializer#paginated? to return 'false'.
EOF
EOF
end
end
def as_json
per_page = collection.try(:per_page) || collection.try(:limit_value) || collection.size
pages_from.each_with_object({}) do |(key, value), hash|
params = query_parameters.merge(page: { number: value, size: per_page }).to_query
hash[key] = "#{url(adapter_options)}?#{params}"
end
{
self: location_url,
first: first_page_url,
prev: prev_page_url,
next: next_page_url,
last: last_page_url
}
end
protected
@ -34,25 +35,39 @@ module ActiveModelSerializers
private
def pages_from
return {} if collection.total_pages <= FIRST_PAGE
def location_url
url_for_page(collection.current_page)
end
{}.tap do |pages|
pages[:self] = collection.current_page
def first_page_url
url_for_page(1)
end
unless collection.current_page == FIRST_PAGE
pages[:first] = FIRST_PAGE
pages[:prev] = collection.current_page - FIRST_PAGE
end
unless collection.current_page == collection.total_pages
pages[:next] = collection.current_page + FIRST_PAGE
pages[:last] = collection.total_pages
end
def last_page_url
if collection.total_pages == 0
url_for_page(FIRST_PAGE)
else
url_for_page(collection.total_pages)
end
end
def url(options)
def prev_page_url
return nil if collection.current_page == FIRST_PAGE
url_for_page(collection.current_page - FIRST_PAGE)
end
def next_page_url
return nil if collection.total_pages == 0 || collection.current_page == collection.total_pages
url_for_page(collection.next_page)
end
def url_for_page(number)
params = query_parameters.dup
params[:page] = { size: per_page, number: number }
"#{url(adapter_options)}?#{params.to_query}"
end
def url(options = {})
@url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
end
@ -63,6 +78,10 @@ module ActiveModelSerializers
def query_parameters
@query_parameters ||= context.query_parameters
end
def per_page
@per_page ||= collection.try(:per_page) || collection.try(:limit_value) || collection.size
end
end
end
end

View File

@ -43,10 +43,16 @@ module ActiveModelSerializers
end
def data_for_one(association)
if association.belongs_to? &&
parent_serializer.object.respond_to?(association.reflection.foreign_key)
id = parent_serializer.object.send(association.reflection.foreign_key)
type = association.reflection.type.to_s
if belongs_to_id_on_self?(association)
id = parent_serializer.read_attribute_for_serialization(association.reflection.foreign_key)
type =
if association.polymorphic?
# We can't infer resource type for polymorphic relationships from the serializer.
# We can ONLY know a polymorphic resource type by inspecting each resource.
association.lazy_association.serializer.json_key
else
association.reflection.type.to_s
end
ResourceIdentifier.for_type_with_id(type, id, serializable_resource_options)
else
# TODO(BF): Process relationship without evaluating lazy_association
@ -86,6 +92,12 @@ module ActiveModelSerializers
meta = association.meta
meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
end
def belongs_to_id_on_self?(association)
parent_serializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship &&
association.belongs_to? &&
parent_serializer.object.respond_to?(association.reflection.foreign_key)
end
end
end
end

View File

@ -2,32 +2,34 @@ module ActiveModelSerializers
module Adapter
class JsonApi
class ResourceIdentifier
def self.type_for(class_name, serializer_type = nil, transform_options = {})
if serializer_type
raw_type = serializer_type
else
inflection =
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
:singularize
else
:pluralize
end
raw_type = class_name.underscore
raw_type = ActiveSupport::Inflector.public_send(inflection, raw_type)
raw_type
.gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
raw_type
end
def self.type_for(serializer, serializer_type = nil, transform_options = {})
raw_type = serializer_type ? serializer_type : raw_type_from_serializer_object(serializer.object)
JsonApi.send(:transform_key_casing!, raw_type, transform_options)
end
def self.for_type_with_id(type, id, options)
return nil if id.blank?
{
id: id.to_s,
type: type_for(:no_class_needed, type, options)
}
type = inflect_type(type)
type = type_for(:no_class_needed, type, options)
if id.blank?
{ type: type }
else
{ id: id.to_s, type: type }
end
end
def self.raw_type_from_serializer_object(object)
class_name = object.class.name # should use model_name
raw_type = class_name.underscore
raw_type = inflect_type(raw_type)
raw_type
.gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
raw_type
end
def self.inflect_type(type)
singularize = ActiveModelSerializers.config.jsonapi_resource_type == :singular
inflection = singularize ? :singularize : :pluralize
ActiveSupport::Inflector.public_send(inflection, type)
end
# {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects}
@ -37,8 +39,11 @@ module ActiveModelSerializers
end
def as_json
return nil if id.blank?
{ id: id, type: type }
if id.blank?
{ type: type }
else
{ id: id.to_s, type: type }
end
end
protected
@ -48,7 +53,8 @@ module ActiveModelSerializers
private
def type_for(serializer, transform_options)
self.class.type_for(serializer.object.class.name, serializer._type, transform_options)
serializer_type = serializer._type
self.class.type_for(serializer, serializer_type, transform_options)
end
def id_for(serializer)

View File

@ -5,6 +5,8 @@ require 'action_controller/serialization'
module ActiveModelSerializers
class Railtie < Rails::Railtie
config.eager_load_namespaces << ActiveModelSerializers
config.to_prepare do
ActiveModel::Serializer.serializers_cache.clear
end

View File

@ -45,7 +45,7 @@ module ActionController
response = JSON.parse(@response.body)
expected = {
'restriction_for_id' => '67',
'restriction_for_type' => 'discounts',
'restriction_for_type' => 'Discount',
'restricted_to_id' => nil,
'restricted_to_type' => nil
}

View File

@ -58,8 +58,10 @@ module ActionController
assert_equal expected_links, response['links']
end
def test_render_only_last_and_next_pagination_links
def test_render_only_first_last_and_next_pagination_links
expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
'prev' => nil,
'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2" }
get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 } }
@ -78,17 +80,21 @@ module ActionController
assert_equal expected_links, response['links']
end
def test_render_only_prev_and_first_pagination_links
def test_render_only_prev_first_and_last_pagination_links
expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1" }
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
'next' => nil,
'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1" }
get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 } }
response = JSON.parse(@response.body)
assert_equal expected_links, response['links']
end
def test_render_only_last_and_next_pagination_links_with_additional_params
def test_render_only_first_last_and_next_pagination_links_with_additional_params
expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
'prev' => nil,
'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional",
'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional" }
get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 }, teste: 'additional' }
@ -96,10 +102,12 @@ module ActionController
assert_equal expected_links, response['links']
end
def test_render_only_prev_and_first_pagination_links_with_additional_params
def test_render_only_prev_first_and_last_pagination_links_with_additional_params
expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional",
'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1&teste=additional",
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1&teste=additional" }
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1&teste=additional",
'next' => nil,
'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional" }
get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 }, teste: 'additional' }
response = JSON.parse(@response.body)
assert_equal expected_links, response['links']

View File

@ -457,13 +457,19 @@ module ActionController
end
def test_render_event_is_emitted
subscriber = ::ActiveSupport::Notifications.subscribe('render.active_model_serializers') do |name|
@name = name
subscriber = ::ActiveSupport::Notifications.subscribe('render.active_model_serializers') do |subscribed_event|
@subscribed_event = subscribed_event
end
get :render_using_implicit_serializer
assert_equal 'render.active_model_serializers', @name
subscribed_event_name =
if @subscribed_event.is_a?(String)
@subscribed_event
else
@subscribed_event.name # is a ActiveSupport::Notifications::Event
end
assert_equal 'render.active_model_serializers', subscribed_event_name
ensure
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
end

View File

@ -1,43 +0,0 @@
require 'test_helper'
module ActiveModelSerializers
module Adapter
class JsonApi
class HasManyEmbedIdsTest < ActiveSupport::TestCase
def setup
@author = Author.new(name: 'Steve K.')
@author.bio = nil
@author.roles = nil
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
@author.posts = [@first_post, @second_post]
@first_post.author = @author
@second_post.author = @author
@first_post.comments = []
@second_post.comments = []
@blog = Blog.new(id: 23, name: 'AMS Blog')
@first_post.blog = @blog
@second_post.blog = nil
@serializer = AuthorSerializer.new(@author)
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer)
end
def test_includes_comment_ids
expected = {
data: [
{ type: 'posts', id: '1' },
{ type: 'posts', id: '2' }
]
}
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:posts])
end
def test_no_includes_linked_comments
assert_nil @adapter.serializable_hash[:linked]
end
end
end
end
end

View File

@ -6,7 +6,7 @@ module ActiveModel
class JsonApi
class IncludeParamTest < ActiveSupport::TestCase
IncludeParamAuthor = Class.new(::Model) do
associations :tags, :posts
associations :tags, :posts, :roles
end
class CustomCommentLoader
@ -51,14 +51,19 @@ module ActiveModel
include_data :if_sideloaded
IncludeParamAuthorSerializer.comment_loader.all
end
has_many :roles, key: :granted_roles do
include_data :if_sideloaded
end
end
def setup
IncludeParamAuthorSerializer.comment_loader = Class.new(CustomCommentLoader).new
@tag = Tag.new(id: 1337, name: 'mytag')
@role = Role.new(id: 1337, name: 'myrole')
@author = IncludeParamAuthor.new(
id: 1337,
tags: [@tag]
tags: [@tag],
roles: [@role]
)
end
@ -105,6 +110,31 @@ module ActiveModel
assert_equal(expected, hash[:included])
end
def test_sideloads_included_when_using_key
expected = [
{
id: '1337',
type: 'roles',
attributes: {
name: 'myrole',
description: nil,
slug: 'myrole-1337'
},
relationships: {
author: { data: nil }
}
}
]
hash = result(include: :granted_roles)
assert_equal(expected, hash[:included])
end
def test_sideloads_not_included_when_using_name_when_key_defined
hash = result(include: :roles)
assert_nil(hash[:included])
end
def test_nested_relationship
expected = {
data: [

View File

@ -17,7 +17,21 @@ module ActiveModelSerializers
link :yet_another do
"http://example.com/resource/#{object.id}"
end
link :conditional1, if: -> { instance_truth } do
"http://example.com/conditional1/#{object.id}"
end
link :conditional2, if: :instance_falsey do
"http://example.com/conditional2/#{object.id}"
end
link(:nil) { nil }
def instance_truth
true
end
def instance_falsey
false
end
end
def setup
@ -85,7 +99,8 @@ module ActiveModelSerializers
:"link-authors" => 'http://example.com/link_authors',
resource: 'http://example.com/resource',
posts: 'http://example.com/link_authors/1337/posts',
:"yet-another" => 'http://example.com/resource/1337'
:"yet-another" => 'http://example.com/resource/1337',
conditional1: 'http://example.com/conditional1/1337'
}
assert_equal(expected, hash[:data][:links])
end

View File

@ -54,6 +54,16 @@ module ActiveModelSerializers
}
end
def empty_collection_links
{
self: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
prev: nil,
next: nil,
last: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2"
}
end
def links
{
links: {
@ -71,7 +81,9 @@ module ActiveModelSerializers
links: {
self: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2",
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2"
prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
next: nil,
last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2"
}
}
end
@ -108,10 +120,10 @@ module ActiveModelSerializers
end
end
def expected_response_with_no_data_pagination_links
def expected_response_with_empty_collection_pagination_links
{}.tap do |hash|
hash[:data] = []
hash[:links] = {}
hash.merge! links: empty_collection_links
end
end
@ -139,7 +151,7 @@ module ActiveModelSerializers
adapter = load_adapter(using_kaminari(1), mock_request)
assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
end
def test_pagination_links_when_zero_results_will_paginate
@ -147,7 +159,7 @@ module ActiveModelSerializers
adapter = load_adapter(using_will_paginate(1), mock_request)
assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
end
def test_last_page_pagination_links_using_kaminari
@ -171,10 +183,11 @@ module ActiveModelSerializers
def test_raises_descriptive_error_when_serialization_context_unset
render_options = { adapter: :json_api }
adapter = serializable(using_kaminari, render_options)
exception = assert_raises do
exception_class = ActiveModelSerializers::Adapter::JsonApi::PaginationLinks::MissingSerializationContextError
exception = assert_raises(exception_class) do
adapter.as_json
end
exception_class = ActiveModelSerializers::Adapter::JsonApi::PaginationLinks::MissingSerializationContextError
assert_equal exception_class, exception.class
assert_match(/CollectionSerializer#paginated\?/, exception.message)
end

View File

@ -125,7 +125,7 @@ module ActiveModelSerializers
src: 'http://example.com/images/productivity.png',
author_id: nil,
photographer_id: '9',
photographer_type: 'people',
photographer_type: 'Person',
comment_ids: %w(1 2)
}
assert_equal(expected, parsed_hash)

View File

@ -1,110 +0,0 @@
require 'test_helper'
module ActiveModelSerializers
module Adapter
class JsonApi
class ResourceIdentifierTest < ActiveSupport::TestCase
class WithDefinedTypeSerializer < ActiveModel::Serializer
type 'with_defined_type'
end
class WithDefinedIdSerializer < ActiveModel::Serializer
def id
'special_id'
end
end
class FragmentedSerializer < ActiveModel::Serializer
cache only: :id
def id
'special_id'
end
end
setup do
@model = Author.new(id: 1, name: 'Steve K.')
ActionController::Base.cache_store.clear
end
def test_defined_type
test_type(WithDefinedTypeSerializer, 'with-defined-type')
end
def test_singular_type
test_type_inflection(AuthorSerializer, 'author', :singular)
end
def test_plural_type
test_type_inflection(AuthorSerializer, 'authors', :plural)
end
def test_type_with_namespace
Object.const_set(:Admin, Module.new)
model = Class.new(::Model)
Admin.const_set(:PowerUser, model)
serializer = Class.new(ActiveModel::Serializer)
Admin.const_set(:PowerUserSerializer, serializer)
with_namespace_separator '--' do
admin_user = Admin::PowerUser.new
serializer = Admin::PowerUserSerializer.new(admin_user)
expected = {
id: admin_user.id,
type: 'admin--power-users'
}
identifier = ResourceIdentifier.new(serializer, {})
actual = identifier.as_json
assert_equal(expected, actual)
end
end
def test_id_defined_on_object
test_id(AuthorSerializer, @model.id.to_s)
end
def test_id_defined_on_serializer
test_id(WithDefinedIdSerializer, 'special_id')
end
def test_id_defined_on_fragmented
test_id(FragmentedSerializer, 'special_id')
end
private
def test_type_inflection(serializer_class, expected_type, inflection)
original_inflection = ActiveModelSerializers.config.jsonapi_resource_type
ActiveModelSerializers.config.jsonapi_resource_type = inflection
test_type(serializer_class, expected_type)
ensure
ActiveModelSerializers.config.jsonapi_resource_type = original_inflection
end
def test_type(serializer_class, expected_type)
serializer = serializer_class.new(@model)
resource_identifier = ResourceIdentifier.new(serializer, nil)
expected = {
id: @model.id.to_s,
type: expected_type
}
assert_equal(expected, resource_identifier.as_json)
end
def test_id(serializer_class, id)
serializer = serializer_class.new(@model)
resource_identifier = ResourceIdentifier.new(serializer, nil)
inflection = ActiveModelSerializers.config.jsonapi_resource_type
type = @model.class.model_name.send(inflection)
expected = {
id: id,
type: type
}
assert_equal(expected, resource_identifier.as_json)
end
end
end
end
end

View File

@ -1,59 +1,191 @@
require 'test_helper'
module ActiveModel
class Serializer
module Adapter
class JsonApi
class TypeTest < ActiveSupport::TestCase
class StringTypeSerializer < ActiveModel::Serializer
attribute :name
type 'profile'
end
module ActiveModelSerializers
module Adapter
class JsonApi
class TypeTest < ActiveSupport::TestCase
class StringTypeSerializer < ActiveModel::Serializer
attribute :name
type 'profile'
end
class SymbolTypeSerializer < ActiveModel::Serializer
attribute :name
type :profile
end
class SymbolTypeSerializer < ActiveModel::Serializer
attribute :name
type :profile
end
setup do
@author = Author.new(id: 1, name: 'Steve K.')
end
setup do
@author = Author.new(id: 1, name: 'Steve K.')
end
def test_config_plural
with_jsonapi_resource_type :plural do
assert_type(@author, 'authors')
end
def test_config_plural
with_jsonapi_inflection :plural do
assert_type(@author, 'authors')
end
end
def test_config_singular
with_jsonapi_resource_type :singular do
assert_type(@author, 'author')
end
def test_config_singular
with_jsonapi_inflection :singular do
assert_type(@author, 'author')
end
end
def test_explicit_string_type_value
assert_type(@author, 'profile', serializer: StringTypeSerializer)
def test_explicit_string_type_value
assert_type(@author, 'profile', serializer: StringTypeSerializer)
end
def test_explicit_symbol_type_value
assert_type(@author, 'profile', serializer: SymbolTypeSerializer)
end
private
def assert_type(resource, expected_type, opts = {})
opts = opts.reverse_merge(adapter: :json_api)
hash = serializable(resource, opts).serializable_hash
assert_equal(expected_type, hash.fetch(:data).fetch(:type))
end
end
class ResourceIdentifierTest < ActiveSupport::TestCase
class WithDefinedTypeSerializer < ActiveModel::Serializer
type 'with_defined_types'
end
class WithDefinedIdSerializer < ActiveModel::Serializer
def id
'special_id'
end
end
def test_explicit_symbol_type_value
assert_type(@author, 'profile', serializer: SymbolTypeSerializer)
class FragmentedSerializer < ActiveModel::Serializer
cache only: :id
def id
'special_id'
end
end
private
setup do
@model = Author.new(id: 1, name: 'Steve K.')
ActionController::Base.cache_store.clear
end
def assert_type(resource, expected_type, opts = {})
opts = opts.reverse_merge(adapter: :json_api)
hash = serializable(resource, opts).serializable_hash
assert_equal(expected_type, hash.fetch(:data).fetch(:type))
def test_defined_type
actual = with_jsonapi_inflection :plural do
actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
end
expected = { id: expected_model_id(@model), type: 'with-defined-types' }
assert_equal actual, expected
end
def with_jsonapi_resource_type(inflection)
old_inflection = ActiveModelSerializers.config.jsonapi_resource_type
ActiveModelSerializers.config.jsonapi_resource_type = inflection
yield
ensure
ActiveModelSerializers.config.jsonapi_resource_type = old_inflection
def test_defined_type_not_inflected
actual = with_jsonapi_inflection :singular do
actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
end
expected = { id: expected_model_id(@model), type: 'with-defined-types' }
assert_equal actual, expected
end
def test_singular_type
actual = with_jsonapi_inflection :singular do
actual_resource_identifier_object(AuthorSerializer, @model)
end
expected = { id: expected_model_id(@model), type: 'author' }
assert_equal actual, expected
end
def test_plural_type
actual = with_jsonapi_inflection :plural do
actual_resource_identifier_object(AuthorSerializer, @model)
end
expected = { id: expected_model_id(@model), type: 'authors' }
assert_equal actual, expected
end
def test_type_with_namespace
Object.const_set(:Admin, Module.new)
model = Class.new(::Model)
Admin.const_set(:PowerUser, model)
serializer = Class.new(ActiveModel::Serializer)
Admin.const_set(:PowerUserSerializer, serializer)
with_namespace_separator '--' do
admin_user = Admin::PowerUser.new
serializer = Admin::PowerUserSerializer.new(admin_user)
expected = {
id: admin_user.id,
type: 'admin--power-users'
}
identifier = ResourceIdentifier.new(serializer, {})
actual = identifier.as_json
assert_equal(expected, actual)
end
end
def test_id_defined_on_object
actual = actual_resource_identifier_object(AuthorSerializer, @model)
expected = { id: @model.id.to_s, type: expected_model_type(@model) }
assert_equal actual, expected
end
def test_blank_id
model = Author.new(id: nil, name: 'Steve K.')
actual = actual_resource_identifier_object(AuthorSerializer, model)
expected = { type: expected_model_type(model) }
assert_equal actual, expected
end
def test_for_type_with_id
id = 1
actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
expected = { id: '1', type: 'admin-users' }
assert_equal actual, expected
end
def test_for_type_with_id_given_blank_id
id = ''
actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
expected = { type: 'admin-users' }
assert_equal actual, expected
end
def test_for_type_with_id_inflected
id = 2
actual = with_jsonapi_inflection :singular do
ResourceIdentifier.for_type_with_id('admin_users', id, {})
end
expected = { id: '2', type: 'admin-user' }
assert_equal actual, expected
end
def test_id_defined_on_serializer
actual = actual_resource_identifier_object(WithDefinedIdSerializer, @model)
expected = { id: 'special_id', type: expected_model_type(@model) }
assert_equal actual, expected
end
def test_id_defined_on_fragmented
actual = actual_resource_identifier_object(FragmentedSerializer, @model)
expected = { id: 'special_id', type: expected_model_type(@model) }
assert_equal actual, expected
end
private
def actual_resource_identifier_object(serializer_class, model)
serializer = serializer_class.new(model)
resource_identifier = ResourceIdentifier.new(serializer, nil)
resource_identifier.as_json
end
def expected_model_type(model, inflection = ActiveModelSerializers.config.jsonapi_resource_type)
with_jsonapi_inflection inflection do
model.class.model_name.send(inflection)
end
end
def expected_model_id(model)
model.id.to_s
end
end
end

View File

@ -165,6 +165,53 @@ module ActiveModel
assert_equal(expected, serialization(@picture, :json_api))
end
def test_json_api_serialization_with_polymorphic_belongs_to
expected = {
data: {
id: '1',
type: 'poly-tags',
attributes: { phrase: 'foo' },
relationships: {
:"object-tags" => {
data: [
{ id: '1', type: 'object-tags' },
{ id: '5', type: 'object-tags' }
]
}
}
},
included: [
{
id: '1',
type: 'object-tags',
relationships: {
taggable: {
data: { id: '42', type: 'employees' }
}
}
},
{
id: '42',
type: 'employees'
},
{
id: '5',
type: 'object-tags',
relationships: {
taggable: {
data: { id: '1', type: 'pictures' }
}
}
},
{
id: '1',
type: 'pictures'
}
]
}
assert_equal(expected, tag_serialization(:json_api))
end
end
end
end

View File

@ -415,7 +415,7 @@ module ActiveModelSerializers
adapter_options = {}
adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
serializers.serializable_hash(adapter_options, options, adapter_instance)
cached_attributes = adapter_options.fetch(:cached_attributes).with_indifferent_access
cached_attributes = options.fetch(:cached_attributes).with_indifferent_access
include_directive = ActiveModelSerializers.default_include_directive
manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive).with_indifferent_access
@ -446,9 +446,9 @@ module ActiveModelSerializers
serializers.serializable_hash(adapter_options, options, adapter_instance)
# Should find something with read_multi now
adapter_options = {}
options = {}
serializers.serializable_hash(adapter_options, options, adapter_instance)
cached_attributes = adapter_options.fetch(:cached_attributes)
cached_attributes = options.fetch(:cached_attributes)
include_directive = ActiveModelSerializers.default_include_directive
manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)

View File

@ -93,12 +93,16 @@ module ActiveModel
resource = []
resource.define_singleton_method(:name) { nil }
serializer = collection_serializer.new(resource)
assert_nil serializer.json_key
assert_raise ArgumentError do
serializer.json_key
end
end
def test_json_key_with_resource_without_name_and_no_serializers
serializer = collection_serializer.new([])
assert_nil serializer.json_key
assert_raise ArgumentError do
serializer.json_key
end
end
def test_json_key_with_empty_resources_with_serializer

View File

@ -89,7 +89,7 @@ class ObjectTag < ActiveRecord::Base
end
class PolymorphicObjectTagSerializer < ActiveModel::Serializer
attributes :id
has_many :taggable, serializer: PolymorphicSimpleSerializer, polymorphic: true
belongs_to :taggable, serializer: PolymorphicSimpleSerializer, polymorphic: true
end
class PolyTag < ActiveRecord::Base
@ -109,5 +109,5 @@ class PolymorphicHasManySerializer < ActiveModel::Serializer
end
class PolymorphicBelongsToSerializer < ActiveModel::Serializer
attributes :id, :title
has_one :imageable, serializer: PolymorphicHasManySerializer, polymorphic: true
belongs_to :imageable, serializer: PolymorphicHasManySerializer, polymorphic: true
end

View File

@ -159,12 +159,56 @@ module ActiveModel
end
end
actual = serializable(post, adapter: :json_api, serializer: BelongsToBlogModelSerializer).as_json
actual =
begin
original_option = BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
serializable(post, adapter: :json_api, serializer: BelongsToBlogModelSerializer).as_json
ensure
BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
end
expected = { data: { id: '1', type: 'posts', relationships: { blog: { data: { id: '5', type: 'blogs' } } } } }
assert_equal expected, actual
end
class ExternalBlog < Blog
attributes :external_id
end
class BelongsToExternalBlogModel < ::Model
attributes :id, :title, :external_blog_id
associations :external_blog
end
class BelongsToExternalBlogModelSerializer < ActiveModel::Serializer
type :posts
belongs_to :external_blog
def external_blog_id
object.external_blog.external_id
end
end
def test_belongs_to_allows_id_overwriting
attributes = {
id: 1,
title: 'Title',
external_blog: ExternalBlog.new(id: 5, external_id: 6)
}
post = BelongsToExternalBlogModel.new(attributes)
actual =
begin
original_option = BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
serializable(post, adapter: :json_api, serializer: BelongsToExternalBlogModelSerializer).as_json
ensure
BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
end
expected = { data: { id: '1', type: 'posts', relationships: { :'external-blog' => { data: { id: '6', type: 'external-blogs' } } } } }
assert_equal expected, actual
end
class InlineAssociationTestPostSerializer < ActiveModel::Serializer
has_many :comments
has_many :comments, key: :last_comments do
@ -241,6 +285,56 @@ module ActiveModel
end
end
class AssociationsNamespacedSerializersTest < ActiveSupport::TestCase
class Post < ::Model
associations :comments, :author, :description
def latest_comments
comments[0..3]
end
end
class Comment < ::Model; end
class Author < ::Model; end
class Description < ::Model; end
class ResourceNamespace
class PostSerializer < ActiveModel::Serializer
has_many :comments, namespace: ResourceNamespace
has_many :latest_comments, namespace: ResourceNamespace
belongs_to :author, namespace: ResourceNamespace
has_one :description, namespace: ResourceNamespace
end
class CommentSerializer < ActiveModel::Serializer; end
class AuthorSerializer < ActiveModel::Serializer; end
class DescriptionSerializer < ActiveModel::Serializer; end
end
def setup
@comment = Comment.new
@author = Author.new
@description = Description.new
@post = Post.new(comments: [@comment],
author: @author,
description: @description)
@post_serializer = ResourceNamespace::PostSerializer.new(@post)
end
def test_associations_namespaced_serializers
@post_serializer.associations.each do |association|
case association.key
when :comments, :latest_comments
assert_instance_of(ResourceNamespace::CommentSerializer, association.lazy_association.serializer.first)
when :author
assert_instance_of(ResourceNamespace::AuthorSerializer, association.lazy_association.serializer)
when :description
assert_instance_of(ResourceNamespace::DescriptionSerializer, association.lazy_association.serializer)
else
flunk "Unknown association: #{key}"
end
end
end
end
class NestedSerializersTest < ActiveSupport::TestCase
class Post < ::Model
associations :comments, :author, :description

View File

@ -423,5 +423,57 @@ module ActiveModel
end
# rubocop:enable Metrics/AbcSize
end
class ThreadedReflectionTest < ActiveSupport::TestCase
class Post < ::Model
attributes :id, :title, :body
associations :comments
end
class Comment < ::Model
attributes :id, :body
associations :post
end
class CommentSerializer < ActiveModel::Serializer
type 'comment'
attributes :id, :body
has_one :post
end
class PostSerializer < ActiveModel::Serializer
type 'post'
attributes :id, :title, :body
has_many :comments, serializer: CommentSerializer do
sleep 0.1
object.comments
end
end
# per https://github.com/rails-api/active_model_serializers/issues/2270
def test_concurrent_serialization
post1 = Post.new(id: 1, title: 'Post 1 Title', body: 'Post 1 Body')
post1.comments = [Comment.new(id: 1, body: 'Comment on Post 1', post: post1)]
post2 = Post.new(id: 2, title: 'Post 2 Title', body: 'Post 2 Body')
post2.comments = [Comment.new(id: 2, body: 'Comment on Post 2', post: post2)]
serialized_posts = {
first: Set.new,
second: Set.new
}
t1 = Thread.new do
10.times do
serialized_posts[:first] << PostSerializer.new(post1, {}).to_json
end
end
t2 = Thread.new do
10.times do
serialized_posts[:second] << PostSerializer.new(post2, {}).to_json
end
end
t1.join
t2.join
expected_first_post_serialization = '{"id":1,"title":"Post 1 Title","body":"Post 1 Body","comments":[{"id":1,"body":"Comment on Post 1"}]}'
expected_second_post_serialization = '{"id":2,"title":"Post 2 Title","body":"Post 2 Body","comments":[{"id":2,"body":"Comment on Post 2"}]}'
assert_equal [expected_second_post_serialization], serialized_posts[:second].to_a
assert_equal [expected_first_post_serialization], serialized_posts[:first].to_a
end
end
end
end

View File

@ -54,7 +54,7 @@ module TestHelpers
require 'rails'
require 'action_controller/railtie'
@app = Class.new(Rails::Application) do
app = Class.new(Rails::Application) do
config.eager_load = false
config.session_store :cookie_store, key: '_myapp_session'
config.active_support.deprecation = :log
@ -67,8 +67,10 @@ module TestHelpers
config.logger = fake_logger
Rails.application.routes.default_url_options = { host: 'example.com' }
end
@app.respond_to?(:secrets) && @app.secrets.secret_key_base = '3b7cd727ee24e8444053437c36cc66c4'
def app.name; 'IsolatedRailsApp'; end # rubocop:disable Style/SingleLineMethods
app.respond_to?(:secrets) && app.secrets.secret_key_base = '3b7cd727ee24e8444053437c36cc66c4'
@app = app
yield @app if block_given?
@app.initialize!
end

View File

@ -47,6 +47,14 @@ module SerializationTesting
ActiveModelSerializers.config.replace(old_config)
end
def with_jsonapi_inflection(inflection)
original_inflection = ActiveModelSerializers.config.jsonapi_resource_type
ActiveModelSerializers.config.jsonapi_resource_type = inflection
yield
ensure
ActiveModelSerializers.config.jsonapi_resource_type = original_inflection
end
def with_serializer_lookup_disabled
original_serializer_lookup = ActiveModelSerializers.config.serializer_lookup_enabled
ActiveModelSerializers.config.serializer_lookup_enabled = false