minato-rails-serializer 0.1.0
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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +22 -0
- data/MIT-LICENSE +20 -0
- data/README.md +155 -0
- data/Rakefile +5 -0
- data/compose.yml +12 -0
- data/entrypoint.sh +7 -0
- data/lib/minato/rails/serializer/base.rb +62 -0
- data/lib/minato/rails/serializer/railtie.rb +37 -0
- data/lib/minato/rails/serializer/version.rb +9 -0
- data/lib/minato/rails/serializer.rb +5 -0
- data/minato-rails-serializer.gemspec +35 -0
- metadata +87 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e17119448417a63faa76e8a5096b0632d588ac6d08ff854535f1e8f2dded7135
|
4
|
+
data.tar.gz: cfc22d1e98188787a38f9db34c3538ba4b5dc38c3edc923225d2dde6c08df25b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0c8bd8c28eb59cfb4b875865836c2c496f1656aa110d3618ebc77fb1023ff2e1f0b28f62463fac35524e1e73deb5f5de623e43e861b384e3813ee27ca2548711
|
7
|
+
data.tar.gz: 26b23b31e4d1df071b6b316ee604b66253ca6b1cab8f59b4ff58c8b089a880821ac4fcd01d12ff650219d74a6f2d5d41335a7856b5d318910417172972784fdf
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
DisplayCopNames: true
|
6
|
+
DisplayStyleGuide: true
|
7
|
+
ExtraDetails: false
|
8
|
+
NewCops: enable
|
9
|
+
TargetRubyVersion: 3.1
|
10
|
+
|
11
|
+
Metrics/BlockLength:
|
12
|
+
IgnoredMethods: ['describe']
|
13
|
+
Max: 50
|
14
|
+
|
15
|
+
RSpec/EmptyExampleGroup:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
RSpec/ImplicitExpect:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/Documentation:
|
22
|
+
Enabled: false
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
# Minato Rails Serializer
|
2
|
+
|
3
|
+
A lightweight and high-performance JSON serialization layer for Rails, built on top of the Panko Serializer.
|
4
|
+
|
5
|
+
Minato::Rails::Serializer seamlessly integrates with Rails' render json:, offering automatic serializer detection, a simple DSL for root keys, and the flexibility to override behavior directly in the controller, all with a focus on convention over configuration.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```Ruby
|
11
|
+
gem 'minato-rails-serializer'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
```Bash
|
17
|
+
$ bundle install
|
18
|
+
```
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
The gem is designed to be as intuitive as possible, integrating with the standard Rails workflow.
|
22
|
+
|
23
|
+
### 1. Creating a Serializer
|
24
|
+
Create your serializers by inheriting from the `Minato::Rails::Serializer::Base` base class.
|
25
|
+
|
26
|
+
```Ruby
|
27
|
+
# app/serializers/post_serializer.rb
|
28
|
+
class PostSerializer < Minato::Rails::Serializer::Base
|
29
|
+
attributes :id, :title, :body
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
### 2. Basic Rendering in Controllers
|
34
|
+
|
35
|
+
Thanks to the included Railtie, the gem modifies render json: to automatically detect and use the corresponding serializer for your model.
|
36
|
+
|
37
|
+
In your controller, you can simply render the object:
|
38
|
+
|
39
|
+
```Ruby
|
40
|
+
class PostsController < ApplicationController
|
41
|
+
def show
|
42
|
+
@post = Post.find(params[:id])
|
43
|
+
# The gem will automatically look for `PostSerializer`
|
44
|
+
render json: @post
|
45
|
+
end
|
46
|
+
|
47
|
+
def index
|
48
|
+
@posts = Post.all
|
49
|
+
# It also works for collections
|
50
|
+
render json: @posts
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### 3. Using the root DSL
|
56
|
+
You can define a default root key directly in your serializer, which will be used to wrap the JSON output.
|
57
|
+
|
58
|
+
```Ruby
|
59
|
+
# app/serializers/user_serializer.rb
|
60
|
+
class UserSerializer < Minato::Rails::Serializer::Base
|
61
|
+
# Sets 'user' as the root for single objects and infers 'users' for collections
|
62
|
+
root :user
|
63
|
+
|
64
|
+
attributes :id, :name, :email
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
Now, when rendering:
|
69
|
+
|
70
|
+
```Ruby
|
71
|
+
# In a `show` action
|
72
|
+
render json: @user
|
73
|
+
# Output:
|
74
|
+
# {
|
75
|
+
# "user": { "id": 1, "name": "...", "email": "..." }
|
76
|
+
# }
|
77
|
+
|
78
|
+
# In an `index` action
|
79
|
+
render json: @users
|
80
|
+
# Output:
|
81
|
+
# {
|
82
|
+
# "users": [
|
83
|
+
# { "id": 1, "name": "...", "email": "..." },
|
84
|
+
# { "id": 2, "name": "...", "email": "..." }
|
85
|
+
# ]
|
86
|
+
# }
|
87
|
+
```
|
88
|
+
|
89
|
+
You can also specify a custom plural name:
|
90
|
+
|
91
|
+
```Ruby
|
92
|
+
class ProductSerializer < Minato::Rails::Serializer::Base
|
93
|
+
root :product, :products_list
|
94
|
+
|
95
|
+
# ...
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
### 4. Overriding Options in the render Call
|
100
|
+
|
101
|
+
The gem offers full flexibility, allowing you to override the default behavior directly in the render call.
|
102
|
+
|
103
|
+
Overriding the Serializer
|
104
|
+
Use the :serializer option to force the use of a different serializer than the inferred default.
|
105
|
+
|
106
|
+
```Ruby
|
107
|
+
# Assuming an AdminUserSerializer exists with more attributes
|
108
|
+
def show
|
109
|
+
@user = User.find(params[:id])
|
110
|
+
render json: @user, serializer: AdminUserSerializer
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
Overriding the Root Key (:root)
|
115
|
+
Use the :root option to set a custom root key for a specific request, overriding the DSL.
|
116
|
+
|
117
|
+
```Ruby
|
118
|
+
def profile
|
119
|
+
@user = current_user
|
120
|
+
# The output will be wrapped in "profile", ignoring the `root :user` from the DSL.
|
121
|
+
render json: @user, root: :profile
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
Disabling the Root Key
|
126
|
+
To remove the root key (even if defined in the DSL), pass root: false.
|
127
|
+
|
128
|
+
```Ruby
|
129
|
+
def show
|
130
|
+
@user = User.find(params[:id])
|
131
|
+
# Returns the JSON object without any root key
|
132
|
+
render json: @user, root: false
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
## Development
|
137
|
+
|
138
|
+
This project uses Docker and Docker Compose to ensure a consistent development and testing environment.
|
139
|
+
|
140
|
+
**Run the test suite:**
|
141
|
+
|
142
|
+
```bash
|
143
|
+
$ docker compose run run minato-rails-serializer
|
144
|
+
```
|
145
|
+
|
146
|
+
The entrypoint script defined in `compose.yml` will automatically create, migrate, and prepare the test database for the dummy application before the RSpec suite is executed. Manual database setup is no longer required.
|
147
|
+
|
148
|
+
To open an interactive shell inside the container for debugging or running other commands (like `rails c` from the dummy app), use:
|
149
|
+
|
150
|
+
```bash
|
151
|
+
$ docker compose run minato-rails-serializer sh
|
152
|
+
```
|
153
|
+
|
154
|
+
## License
|
155
|
+
The gem is available as open source under the terms of the MIT License.
|
data/Rakefile
ADDED
data/compose.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
services:
|
2
|
+
minato-rails-serializer:
|
3
|
+
image: us-east1-docker.pkg.dev/minato-cloud/images/ruby-minato:1.0.0-dev
|
4
|
+
working_dir: /usr/src/app
|
5
|
+
volumes:
|
6
|
+
- .:/usr/src/app:cached
|
7
|
+
- bundle:/home/rails/.bundle
|
8
|
+
entrypoint: ./entrypoint.sh
|
9
|
+
command: rspec
|
10
|
+
|
11
|
+
volumes:
|
12
|
+
bundle:
|
data/entrypoint.sh
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'panko_serializer'
|
4
|
+
|
5
|
+
module Minato
|
6
|
+
module Rails
|
7
|
+
module Serializer
|
8
|
+
class Base < Panko::Serializer
|
9
|
+
class << self
|
10
|
+
def render(data, options = {})
|
11
|
+
rendered = render_data(data, options)
|
12
|
+
root = get_root(data, options)
|
13
|
+
return { root => rendered } if root.present?
|
14
|
+
|
15
|
+
rendered
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def root(name, plural_name = nil)
|
21
|
+
plural_root_name = plural_name || (name.pluralize if name.is_a?(String))
|
22
|
+
define_singleton_method(:root_name) { name }
|
23
|
+
define_singleton_method(:plural_root_name) { plural_root_name }
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_accessor :root_name, :plural_root_name
|
29
|
+
|
30
|
+
def render_data(data, options = {})
|
31
|
+
if data.is_a?(Array) || data.is_a?(ActiveRecord::Relation) || data.respond_to?(:each)
|
32
|
+
return render_array(data, options)
|
33
|
+
end
|
34
|
+
|
35
|
+
render_object(data, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def render_array(data, options = {})
|
39
|
+
return [] if data.blank?
|
40
|
+
|
41
|
+
Panko::ArraySerializer.new(data, options.merge(each_serializer: self)).to_a
|
42
|
+
end
|
43
|
+
|
44
|
+
def render_object(data, options = {})
|
45
|
+
return nil if data.nil?
|
46
|
+
|
47
|
+
new(options[:options] || {}).serialize(data)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_root(data, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
|
51
|
+
return nil if options[:root] == false
|
52
|
+
return options[:root] if options.key?(:root)
|
53
|
+
return nil if root_name.nil?
|
54
|
+
|
55
|
+
plural = plural_root_name || root_name&.to_s&.pluralize
|
56
|
+
data.is_a?(Enumerable) ? plural : root_name
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/minato/rails/serializer/railtie.rb
|
4
|
+
|
5
|
+
require 'rails/railtie'
|
6
|
+
|
7
|
+
module Minato
|
8
|
+
module Rails
|
9
|
+
module Serializer
|
10
|
+
class Railtie < ::Rails::Railtie
|
11
|
+
initializer 'minato.rails.serializer.add_json_renderer' do
|
12
|
+
ActionController::Renderers.remove(:json)
|
13
|
+
|
14
|
+
find_serializer_for_model = lambda do |obj|
|
15
|
+
klass = obj.is_a?(Enumerable) ? obj.first&.class : obj.class
|
16
|
+
return nil unless klass && defined?(ActiveRecord::Base) && klass < ActiveRecord::Base
|
17
|
+
|
18
|
+
"#{klass.name}Serializer".safe_constantize
|
19
|
+
end
|
20
|
+
|
21
|
+
ActionController::Renderers.add :json do |object, options|
|
22
|
+
self.content_type ||= Mime[:json]
|
23
|
+
serializer = options[:serializer].presence || find_serializer_for_model.call(object)
|
24
|
+
|
25
|
+
if serializer
|
26
|
+
serializer_options = options.slice(:root)
|
27
|
+
serializer.render(object, serializer_options).to_json
|
28
|
+
else
|
29
|
+
object = { options[:root] => object } if options[:root].present?
|
30
|
+
object.to_json(options.except(:root))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/minato/rails/serializer/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'minato-rails-serializer'
|
7
|
+
spec.version = Minato::Rails::Serializer::VERSION
|
8
|
+
spec.authors = ['Ferreri']
|
9
|
+
spec.email = ['contato@ferreri.co']
|
10
|
+
|
11
|
+
spec.summary = 'Serializer for Minato Rails Apps.'
|
12
|
+
spec.homepage = 'https://gitlab.com/ferreri/minato/minato-rails-serializer'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.required_ruby_version = '>= 3.1.0'
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://gitlab.com/ferreri/minato/minato-rails-serializer'
|
18
|
+
spec.metadata['changelog_uri'] = 'https://gitlab.com/ferreri/minato/minato-rails-serializer/-/blob/main/CHANGELOG.md?ref_type=heads'
|
19
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
(File.expand_path(f) == __FILE__) ||
|
26
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
spec.bindir = 'exe'
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
spec.add_dependency 'panko_serializer', '>= 0.8.3'
|
34
|
+
spec.add_dependency 'rails', '>= 7.0.0'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: minato-rails-serializer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ferreri
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-09-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: panko_serializer
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.8.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.8.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 7.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 7.0.0
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- contato@ferreri.co
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".rspec"
|
49
|
+
- ".rubocop.yml"
|
50
|
+
- MIT-LICENSE
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- compose.yml
|
54
|
+
- entrypoint.sh
|
55
|
+
- lib/minato/rails/serializer.rb
|
56
|
+
- lib/minato/rails/serializer/base.rb
|
57
|
+
- lib/minato/rails/serializer/railtie.rb
|
58
|
+
- lib/minato/rails/serializer/version.rb
|
59
|
+
- minato-rails-serializer.gemspec
|
60
|
+
homepage: https://gitlab.com/ferreri/minato/minato-rails-serializer
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata:
|
64
|
+
homepage_uri: https://gitlab.com/ferreri/minato/minato-rails-serializer
|
65
|
+
source_code_uri: https://gitlab.com/ferreri/minato/minato-rails-serializer
|
66
|
+
changelog_uri: https://gitlab.com/ferreri/minato/minato-rails-serializer/-/blob/main/CHANGELOG.md?ref_type=heads
|
67
|
+
rubygems_mfa_required: 'true'
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 3.1.0
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubygems_version: 3.4.19
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Serializer for Minato Rails Apps.
|
87
|
+
test_files: []
|