active_model_serializers_rails_2.3 0.9.0.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +87 -0
- data/CONTRIBUTING.md +20 -0
- data/DESIGN.textile +586 -0
- data/MIT-LICENSE +21 -0
- data/README.md +793 -0
- data/lib/active_model/array_serializer.rb +60 -0
- data/lib/active_model/default_serializer.rb +27 -0
- data/lib/active_model/serializable.rb +25 -0
- data/lib/active_model/serializer.rb +220 -0
- data/lib/active_model/serializer/associations.rb +98 -0
- data/lib/active_model/serializer/config.rb +31 -0
- data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +14 -0
- data/lib/active_model/serializer/generators/serializer/templates/controller.rb +93 -0
- data/lib/active_model/serializer/railtie.rb +10 -0
- data/lib/active_model/serializer/version.rb +5 -0
- data/lib/active_model/serializer_support.rb +5 -0
- data/lib/active_model_serializers.rb +33 -0
- data/test/coverage_setup.rb +15 -0
- data/test/fixtures/active_record.rb +92 -0
- data/test/fixtures/poro.rb +64 -0
- data/test/integration/active_record/active_record_test.rb +77 -0
- data/test/test_app.rb +11 -0
- data/test/test_helper.rb +13 -0
- data/test/unit/active_model/array_serializer/meta_test.rb +53 -0
- data/test/unit/active_model/array_serializer/root_test.rb +102 -0
- data/test/unit/active_model/array_serializer/scope_test.rb +24 -0
- data/test/unit/active_model/array_serializer/serialization_test.rb +182 -0
- data/test/unit/active_model/default_serializer_test.rb +13 -0
- data/test/unit/active_model/serializer/associations/build_serializer_test.rb +21 -0
- data/test/unit/active_model/serializer/associations_test.rb +19 -0
- data/test/unit/active_model/serializer/attributes_test.rb +41 -0
- data/test/unit/active_model/serializer/config_test.rb +86 -0
- data/test/unit/active_model/serializer/filter_test.rb +49 -0
- data/test/unit/active_model/serializer/has_many_test.rb +174 -0
- data/test/unit/active_model/serializer/has_one_test.rb +151 -0
- data/test/unit/active_model/serializer/meta_test.rb +39 -0
- data/test/unit/active_model/serializer/root_test.rb +117 -0
- data/test/unit/active_model/serializer/scope_test.rb +49 -0
- metadata +127 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Generators
|
6
|
+
class ScaffoldControllerGenerator
|
7
|
+
if Rails::VERSION::MAJOR >= 4
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
hook_for :serializer, default: true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<% if namespaced? -%>
|
2
|
+
require_dependency "<%= namespaced_file_path %>/application_controller"
|
3
|
+
|
4
|
+
<% end -%>
|
5
|
+
<% module_namespacing do -%>
|
6
|
+
class <%= controller_class_name %>Controller < ApplicationController
|
7
|
+
before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
|
8
|
+
|
9
|
+
# GET <%= route_url %>
|
10
|
+
# GET <%= route_url %>.json
|
11
|
+
def index
|
12
|
+
@<%= plural_table_name %> = <%= orm_class.all(class_name) %>
|
13
|
+
|
14
|
+
respond_to do |format|
|
15
|
+
format.html # index.html.erb
|
16
|
+
format.json { render json: <%= "@#{plural_table_name}" %> }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# GET <%= route_url %>/1
|
21
|
+
# GET <%= route_url %>/1.json
|
22
|
+
def show
|
23
|
+
respond_to do |format|
|
24
|
+
format.html # show.html.erb
|
25
|
+
format.json { render json: <%= "@#{singular_table_name}" %> }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# GET <%= route_url %>/new
|
30
|
+
def new
|
31
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name) %>
|
32
|
+
end
|
33
|
+
|
34
|
+
# GET <%= route_url %>/1/edit
|
35
|
+
def edit
|
36
|
+
end
|
37
|
+
|
38
|
+
# POST <%= route_url %>
|
39
|
+
# POST <%= route_url %>.json
|
40
|
+
def create
|
41
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
|
42
|
+
|
43
|
+
respond_to do |format|
|
44
|
+
if @<%= orm_instance.save %>
|
45
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
|
46
|
+
format.json { render json: <%= "@#{singular_table_name}" %>, status: :created }
|
47
|
+
else
|
48
|
+
format.html { render action: 'new' }
|
49
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# PATCH/PUT <%= route_url %>/1
|
55
|
+
# PATCH/PUT <%= route_url %>/1.json
|
56
|
+
def update
|
57
|
+
respond_to do |format|
|
58
|
+
if @<%= orm_instance.update("#{singular_table_name}_params") %>
|
59
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
|
60
|
+
format.json { head :no_content }
|
61
|
+
else
|
62
|
+
format.html { render action: 'edit' }
|
63
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# DELETE <%= route_url %>/1
|
69
|
+
# DELETE <%= route_url %>/1.json
|
70
|
+
def destroy
|
71
|
+
@<%= orm_instance.destroy %>
|
72
|
+
respond_to do |format|
|
73
|
+
format.html { redirect_to <%= index_helper %>_url }
|
74
|
+
format.json { head :no_content }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
# Use callbacks to share common setup or constraints between actions.
|
80
|
+
def set_<%= singular_table_name %>
|
81
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
82
|
+
end
|
83
|
+
|
84
|
+
# Never trust parameters from the scary internet, only allow the white list through.
|
85
|
+
def <%= "#{singular_table_name}_params" %>
|
86
|
+
<%- if attributes_names.empty? -%>
|
87
|
+
params[<%= ":#{singular_table_name}" %>]
|
88
|
+
<%- else -%>
|
89
|
+
params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
|
90
|
+
<%- end -%>
|
91
|
+
end
|
92
|
+
end
|
93
|
+
<% end -%>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
initializer 'generators' do |app|
|
4
|
+
app.load_generators
|
5
|
+
require 'active_model/serializer/generators/serializer/serializer_generator'
|
6
|
+
require 'active_model/serializer/generators/serializer/scaffold_controller_generator'
|
7
|
+
require 'active_model/serializer/generators/resource_override'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_model/serializer'
|
4
|
+
require 'active_model/serializer_support'
|
5
|
+
require 'active_model/serializer/version'
|
6
|
+
require 'active_model/serializer/railtie' if defined?(Rails) && defined?(Rails::Railtie)
|
7
|
+
|
8
|
+
ActiveModel::Errors = ActiveRecord::Errors #fix for authlogic gem
|
9
|
+
|
10
|
+
module ActiveSupport
|
11
|
+
module Inflector
|
12
|
+
def safe_constantize(camel_cased_word)
|
13
|
+
begin
|
14
|
+
constantize(camel_cased_word)
|
15
|
+
rescue NameError => e
|
16
|
+
raise unless e.message =~ /(uninitialized constant|wrong constant name) #{const_regexp(camel_cased_word)}$/ ||
|
17
|
+
e.name.to_s == camel_cased_word.to_s
|
18
|
+
rescue ArgumentError => e
|
19
|
+
raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
begin
|
25
|
+
require 'action_controller'
|
26
|
+
require 'action_controller/serialization'
|
27
|
+
|
28
|
+
ActiveSupport.on_load(:action_controller) do
|
29
|
+
include ::ActionController::Serialization
|
30
|
+
end
|
31
|
+
rescue LoadError
|
32
|
+
# rails not installed, continuing
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'simplecov'
|
3
|
+
require 'coveralls'
|
4
|
+
|
5
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
6
|
+
SimpleCov::Formatter::HTMLFormatter,
|
7
|
+
Coveralls::SimpleCov::Formatter
|
8
|
+
]
|
9
|
+
|
10
|
+
SimpleCov.start do
|
11
|
+
add_group "lib", "lib"
|
12
|
+
add_group "test", "test"
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
ActiveRecord::Base.establish_connection(
|
4
|
+
:adapter => 'sqlite3',
|
5
|
+
:database => ':memory:'
|
6
|
+
)
|
7
|
+
|
8
|
+
ActiveRecord::Schema.define do
|
9
|
+
create_table :ar_posts, force: true do |t|
|
10
|
+
t.string :title
|
11
|
+
t.text :body
|
12
|
+
t.belongs_to :ar_section, index: true
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :ar_comments, force: true do |t|
|
17
|
+
t.text :body
|
18
|
+
t.belongs_to :ar_post, index: true
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :ar_tags, force: true do |t|
|
23
|
+
t.string :name
|
24
|
+
end
|
25
|
+
|
26
|
+
create_table :ar_sections, force: true do |t|
|
27
|
+
t.string :name
|
28
|
+
end
|
29
|
+
|
30
|
+
create_table :ar_posts_tags, force: true, id: false do |t|
|
31
|
+
t.references :ar_post, :ar_tag, index: true
|
32
|
+
end
|
33
|
+
|
34
|
+
create_table :ar_comments_tags, force: true, id: false do |t|
|
35
|
+
t.references :ar_comment, :ar_tag, index: true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ARPost < ActiveRecord::Base
|
40
|
+
has_many :ar_comments, class_name: 'ARComment'
|
41
|
+
has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_posts_tags
|
42
|
+
belongs_to :ar_section, class_name: 'ARSection'
|
43
|
+
end
|
44
|
+
|
45
|
+
class ARComment < ActiveRecord::Base
|
46
|
+
belongs_to :ar_post, class_name: 'ARPost'
|
47
|
+
has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_comments_tags
|
48
|
+
end
|
49
|
+
|
50
|
+
class ARTag < ActiveRecord::Base
|
51
|
+
end
|
52
|
+
|
53
|
+
class ARSection < ActiveRecord::Base
|
54
|
+
end
|
55
|
+
|
56
|
+
class ARPostSerializer < ActiveModel::Serializer
|
57
|
+
attributes :title, :body
|
58
|
+
|
59
|
+
has_many :ar_comments, :ar_tags
|
60
|
+
has_one :ar_section
|
61
|
+
end
|
62
|
+
|
63
|
+
class ARCommentSerializer < ActiveModel::Serializer
|
64
|
+
attributes :body
|
65
|
+
|
66
|
+
has_many :ar_tags
|
67
|
+
end
|
68
|
+
|
69
|
+
class ARTagSerializer < ActiveModel::Serializer
|
70
|
+
attributes :name
|
71
|
+
end
|
72
|
+
|
73
|
+
class ARSectionSerializer < ActiveModel::Serializer
|
74
|
+
attributes 'name'
|
75
|
+
end
|
76
|
+
|
77
|
+
ARPost.create(title: 'New post',
|
78
|
+
body: 'A body!!!',
|
79
|
+
ar_section: ARSection.create(name: 'ruby')).tap do |post|
|
80
|
+
|
81
|
+
short_tag = post.ar_tags.create(name: 'short')
|
82
|
+
whiny_tag = post.ar_tags.create(name: 'whiny')
|
83
|
+
happy_tag = ARTag.create(name: 'happy')
|
84
|
+
|
85
|
+
post.ar_comments.create(body: 'what a dumb post').tap do |comment|
|
86
|
+
comment.ar_tags.concat happy_tag, whiny_tag
|
87
|
+
end
|
88
|
+
|
89
|
+
post.ar_comments.create(body: 'i liked it').tap do |comment|
|
90
|
+
comment.ar_tags.concat happy_tag, short_tag
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Model
|
2
|
+
def initialize(hash={})
|
3
|
+
@attributes = hash
|
4
|
+
end
|
5
|
+
|
6
|
+
def read_attribute_for_serialization(name)
|
7
|
+
if name == :id || name == 'id'
|
8
|
+
object_id
|
9
|
+
else
|
10
|
+
@attributes[name]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
###
|
17
|
+
## Models
|
18
|
+
###
|
19
|
+
class User < Model
|
20
|
+
def profile
|
21
|
+
@profile ||= Profile.new(name: 'N1', description: 'D1')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Profile < Model
|
26
|
+
end
|
27
|
+
|
28
|
+
class Post < Model
|
29
|
+
def comments
|
30
|
+
@comments ||= [Comment.new(content: 'C1'),
|
31
|
+
Comment.new(content: 'C2')]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Comment < Model
|
36
|
+
end
|
37
|
+
|
38
|
+
###
|
39
|
+
## Serializers
|
40
|
+
###
|
41
|
+
class UserSerializer < ActiveModel::Serializer
|
42
|
+
attributes :name, :email
|
43
|
+
|
44
|
+
has_one :profile
|
45
|
+
end
|
46
|
+
|
47
|
+
class ProfileSerializer < ActiveModel::Serializer
|
48
|
+
def description
|
49
|
+
description = object.read_attribute_for_serialization(:description)
|
50
|
+
scope ? "#{description} - #{scope}" : description
|
51
|
+
end
|
52
|
+
|
53
|
+
attributes :name, :description
|
54
|
+
end
|
55
|
+
|
56
|
+
class PostSerializer < ActiveModel::Serializer
|
57
|
+
attributes :title, :body
|
58
|
+
|
59
|
+
has_many :comments
|
60
|
+
end
|
61
|
+
|
62
|
+
class CommentSerializer < ActiveModel::Serializer
|
63
|
+
attributes :content
|
64
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'fixtures/active_record'
|
3
|
+
|
4
|
+
module ActiveModel
|
5
|
+
class Serializer
|
6
|
+
class ActiveRecordTest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
@post = ARPost.first
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_serialization_embedding_objects
|
12
|
+
post_serializer = ARPostSerializer.new(@post)
|
13
|
+
|
14
|
+
assert_equal({
|
15
|
+
'ar_post' => {
|
16
|
+
title: 'New post', body: 'A body!!!',
|
17
|
+
ar_comments: [{ body: 'what a dumb post', ar_tags: [{ name: 'happy' }, { name: 'whiny' }] },
|
18
|
+
{ body: 'i liked it', ar_tags: [{:name=>"happy"}, {:name=>"short"}] }],
|
19
|
+
ar_tags: [{ name: 'short' }, { name: 'whiny' }],
|
20
|
+
ar_section: { 'name' => 'ruby' }
|
21
|
+
}
|
22
|
+
}, post_serializer.as_json)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_serialization_embedding_ids
|
26
|
+
post_serializer = ARPostSerializer.new(@post)
|
27
|
+
|
28
|
+
embed(ARPostSerializer, embed: :ids) do
|
29
|
+
assert_equal({
|
30
|
+
'ar_post' => {
|
31
|
+
title: 'New post', body: 'A body!!!',
|
32
|
+
'ar_comment_ids' => [1, 2],
|
33
|
+
'ar_tag_ids' => [1, 2],
|
34
|
+
'ar_section_id' => 1
|
35
|
+
}
|
36
|
+
}, post_serializer.as_json)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_serialization_embedding_ids_including_in_root
|
41
|
+
post_serializer = ARPostSerializer.new(@post)
|
42
|
+
|
43
|
+
embed(ARPostSerializer, embed: :ids, embed_in_root: true) do
|
44
|
+
embed(ARCommentSerializer, embed: :ids, embed_in_root: true) do
|
45
|
+
assert_equal({
|
46
|
+
'ar_post' => {
|
47
|
+
title: 'New post', body: 'A body!!!',
|
48
|
+
'ar_comment_ids' => [1, 2],
|
49
|
+
'ar_tag_ids' => [1, 2],
|
50
|
+
'ar_section_id' => 1
|
51
|
+
},
|
52
|
+
ar_comments: [{ body: 'what a dumb post', 'ar_tag_ids' => [3, 2] },
|
53
|
+
{ body: 'i liked it', 'ar_tag_ids' => [3, 1] }],
|
54
|
+
ar_tags: [{ name: 'happy' }, { name: 'whiny' }, { name: 'short' }],
|
55
|
+
'ar_sections' => [{ 'name' => 'ruby' }]
|
56
|
+
}, post_serializer.as_json)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def embed(serializer_class, options = {})
|
64
|
+
old_assocs = Hash[serializer_class._associations.to_a.map { |(name, association)| [name, association.dup] }]
|
65
|
+
|
66
|
+
serializer_class._associations.each_value do |association|
|
67
|
+
association.embed = options[:embed]
|
68
|
+
association.embed_in_root = options[:embed_in_root]
|
69
|
+
end
|
70
|
+
|
71
|
+
yield
|
72
|
+
ensure
|
73
|
+
serializer_class._associations = old_assocs
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/test/test_app.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
class TestApp < Rails::Application
|
2
|
+
if Rails.version.to_s.first >= '4'
|
3
|
+
config.eager_load = false
|
4
|
+
config.secret_key_base = 'abc123'
|
5
|
+
end
|
6
|
+
|
7
|
+
# Set up a logger to avoid creating a log directory on every run.
|
8
|
+
config.logger = Logger.new(nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
TestApp.initialize!
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'coverage_setup'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'active_model_serializers'
|
5
|
+
require 'fixtures/poro'
|
6
|
+
require 'fixtures/active_record'
|
7
|
+
|
8
|
+
# Ensure backward compatibility with Minitest 4
|
9
|
+
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
|
10
|
+
|
11
|
+
module TestHelper
|
12
|
+
end
|
13
|
+
|