jbuilder 2.11.1 → 2.11.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e3eebf3fe3849616361ae7df9556f466eaf84da813756b8690dfbd5c28d41a1
4
- data.tar.gz: 011c0162b09a94f229673e88bab0d0d466d9552a004afb426f817a02c3af8943
3
+ metadata.gz: 9ce8fbeac8b34ee290535e98a284a1247e2de1b5272c4679c1b89a89ff8149db
4
+ data.tar.gz: cdaeb1302c4755ca43f037328698afe29fe658f2094c99e2c6f81f0000b9368c
5
5
  SHA512:
6
- metadata.gz: 29968e2f35da52dc00db229d0085d77a7d390417bbe3011b005824ff45a1291bca0f45c59d4f40263a3ac236e31ea3fdd0cd78ba01ddef4e51414aea4ac34704
7
- data.tar.gz: '09df7fb01ce2d128b0f45116cc4f2ccb01469031a51b598f6c17c16f58ddbd0c3059095a1a6761a2f26e328b3960def55752d6ed36cca0e2952e393d712e48b3'
6
+ metadata.gz: 6903b1aa13786fd5501d8e667eb7a913ebd469d24ce183a24cdf949a62788b1e598c2e0678c5ed5e369d4232c7720e284850f735c5be6f4691e4ecf42256d21a
7
+ data.tar.gz: 2a40e415a25a4d8680ac00ba81b9984188ef35440869a357db4fd7184d3f0b36d0ce10545a0d5253e6d12374b2f1d51f5a96f1ded1370ec7eddecaee469afc61
@@ -0,0 +1,108 @@
1
+ name: Ruby test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ name: Ruby ${{ matrix.ruby }} (${{ matrix.gemfile }})
8
+ runs-on: ubuntu-20.04
9
+ continue-on-error: ${{ matrix.experimental }}
10
+ env:
11
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
12
+ BUNDLE_JOBS: 4
13
+ BUNDLE_RETRY: 3
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ ruby:
18
+ - "2.2"
19
+ - "2.3"
20
+ - "2.4"
21
+ - "2.5"
22
+ - "2.6"
23
+ - "2.7"
24
+ - "3.0"
25
+
26
+ gemfile:
27
+ - "rails_5_0"
28
+ - "rails_5_1"
29
+ - "rails_5_2"
30
+ - "rails_6_0"
31
+ - "rails_6_1"
32
+ - "rails_head"
33
+
34
+ experimental: [false]
35
+ exclude:
36
+ - ruby: 2.7
37
+ gemfile: rails_5_0
38
+ - ruby: '3.0'
39
+ gemfile: rails_5_0
40
+ - ruby: head
41
+ gemfile: rails_5_0
42
+ - ruby: 2.7
43
+ gemfile: rails_5_1
44
+ - ruby: '3.0'
45
+ gemfile: rails_5_1
46
+ - ruby: head
47
+ gemfile: rails_5_1
48
+ - ruby: 2.2
49
+ gemfile: rails_5_2
50
+ - ruby: 2.7
51
+ gemfile: rails_5_2
52
+ - ruby: '3.0'
53
+ gemfile: rails_5_2
54
+ - ruby: head
55
+ gemfile: rails_5_2
56
+ - ruby: 2.2
57
+ gemfile: rails_6_0
58
+ - ruby: 2.3
59
+ gemfile: rails_6_0
60
+ - ruby: 2.4
61
+ gemfile: rails_6_0
62
+ - ruby: '3.0'
63
+ gemfile: rails_6_0
64
+ - ruby: head
65
+ gemfile: rails_6_0
66
+ - ruby: 2.2
67
+ gemfile: rails_6_1
68
+ - ruby: 2.3
69
+ gemfile: rails_6_1
70
+ - ruby: 2.4
71
+ gemfile: rails_6_1
72
+ - ruby: 2.2
73
+ gemfile: rails_head
74
+ - ruby: 2.3
75
+ gemfile: rails_head
76
+ - ruby: 2.4
77
+ gemfile: rails_head
78
+ - ruby: 2.5
79
+ gemfile: rails_head
80
+ - ruby: 2.6
81
+ gemfile: rails_head
82
+ - ruby: 2.7
83
+ gemfile: rails_head
84
+ experimental: false
85
+ - ruby: '3.0'
86
+ gemfile: rails_head
87
+ experimental: false
88
+ include:
89
+ - ruby: 2.7
90
+ gemfile: rails_head
91
+ experimental: true
92
+ - ruby: '3.0'
93
+ gemfile: rails_head
94
+ experimental: true
95
+ - ruby: head
96
+ gemfile: rails_head
97
+ experimental: true
98
+
99
+ steps:
100
+ - uses: actions/checkout@v2
101
+
102
+ - uses: ruby/setup-ruby@v1
103
+ with:
104
+ ruby-version: ${{ matrix.ruby }}
105
+ bundler-cache: true
106
+
107
+ - name: Ruby test
108
+ run: bundle exec rake
data/Appraisals CHANGED
@@ -15,7 +15,11 @@ if RUBY_VERSION >= "2.5.0"
15
15
  gem "rails", "~> 6.0.0"
16
16
  end
17
17
 
18
+ appraise "rails-6-1" do
19
+ gem "rails", "~> 6.1.0"
20
+ end
21
+
18
22
  appraise "rails-head" do
19
- gem "rails", github: "rails/rails"
23
+ gem "rails", github: "rails/rails", branch: "main"
20
24
  end
21
25
  end
data/CONTRIBUTING.md CHANGED
@@ -1,11 +1,11 @@
1
1
  Contributing to Jbuilder
2
2
  =====================
3
3
 
4
- [![Build Status](https://api.travis-ci.org/rails/jbuilder.svg?branch=master)][travis]
4
+ [![Build Status](https://github.com/rails/jbuilder/workflows/Ruby%20test/badge.svg)][test]
5
5
  [![Gem Version](https://badge.fury.io/rb/jbuilder.svg)][gem]
6
6
  [![Code Climate](https://codeclimate.com/github/rails/jbuilder/badges/gpa.svg)][codeclimate]
7
7
 
8
- [travis]: https://travis-ci.org/rails/jbuilder
8
+ [test]: https://github.com/rails/jbuilder/actions?query=branch%3Amaster
9
9
  [gem]: https://rubygems.org/gems/jbuilder
10
10
  [codeclimate]: https://codeclimate.com/github/rails/jbuilder
11
11
 
@@ -95,7 +95,7 @@ git push origin my-feature-branch -f
95
95
 
96
96
  #### Check on Your Pull Request
97
97
 
98
- Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
98
+ Go back to your pull request after a few minutes and see whether it passed muster with GitHub Actions. Everything should look green, otherwise fix issues and amend your commit as described above.
99
99
 
100
100
  #### Be Patient
101
101
 
data/README.md CHANGED
@@ -108,6 +108,33 @@ json.array! @people, :id, :name
108
108
  # => [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ]
109
109
  ```
110
110
 
111
+ To make a plain array without keys, construct and pass in a standard Ruby array.
112
+
113
+ ```ruby
114
+ my_array = %w(David Jamie)
115
+
116
+ json.people my_array
117
+
118
+ # => "people": [ "David", "Jamie" ]
119
+ ```
120
+
121
+ You don't always have or need a collection when building an array.
122
+
123
+ ```ruby
124
+ json.people do
125
+ json.child! do
126
+ json.id 1
127
+ json.name 'David'
128
+ end
129
+ json.child! do
130
+ json.id 2
131
+ json.name 'Jamie'
132
+ end
133
+ end
134
+
135
+ # => { "people": [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ] }
136
+ ```
137
+
111
138
  Jbuilder objects can be directly nested inside each other. Useful for composing objects.
112
139
 
113
140
  ``` ruby
@@ -137,7 +164,7 @@ company.to_builder.target!
137
164
  ```
138
165
 
139
166
  You can either use Jbuilder stand-alone or directly as an ActionView template
140
- language. When required in Rails, you can create views a la show.json.jbuilder
167
+ language. When required in Rails, you can create views à la show.json.jbuilder
141
168
  (the json is already yielded):
142
169
 
143
170
  ``` ruby
@@ -171,19 +198,19 @@ It's also possible to render collections of partials:
171
198
  json.array! @posts, partial: 'posts/post', as: :post
172
199
 
173
200
  # or
174
-
175
201
  json.partial! 'posts/post', collection: @posts, as: :post
176
202
 
177
203
  # or
178
-
179
204
  json.partial! partial: 'posts/post', collection: @posts, as: :post
180
205
 
181
206
  # or
182
-
183
207
  json.comments @post.comments, partial: 'comments/comment', as: :comment
184
208
  ```
185
209
 
186
- The `as: :some_symbol` is used with partials. It will take care of mapping the passed in object to a variable for the partial. If the value is a collection (either implicitly or explicitly by using the `collection:` option, then each value of the collection is passed to the partial as the variable `some_symbol`. If the value is a singular object, then the object is passed to the partial as the variable `some_symbol`.
210
+ The `as: :some_symbol` is used with partials. It will take care of mapping the passed in object to a variable for the
211
+ partial. If the value is a collection either implicitly or explicitly by using the `collection:` option, then each
212
+ value of the collection is passed to the partial as the variable `some_symbol`. If the value is a singular object,
213
+ then the object is passed to the partial as the variable `some_symbol`.
187
214
 
188
215
  Be sure not to confuse the `as:` option to mean nesting of the partial. For example:
189
216
 
@@ -193,7 +220,7 @@ Be sure not to confuse the `as:` option to mean nesting of the partial. For exam
193
220
  json.partial! @comment, as: :comment
194
221
  ```
195
222
 
196
- is quite different than:
223
+ is quite different from:
197
224
 
198
225
  ```ruby
199
226
  # comment attributes are nested under a "comment" property
@@ -236,6 +263,8 @@ json.bar "bar"
236
263
  # => { "bar": "bar" }
237
264
  ```
238
265
 
266
+ ## Caching
267
+
239
268
  Fragment caching is supported, it uses `Rails.cache` and works like caching in
240
269
  HTML templates:
241
270
 
@@ -253,9 +282,25 @@ json.cache_if! !admin?, ['v1', @person], expires_in: 10.minutes do
253
282
  end
254
283
  ```
255
284
 
256
- If you are rendering fragments for a collection of objects, have a look at
257
- `jbuilder_cache_multi` gem. It uses fetch_multi (>= Rails 4.1) to fetch
258
- multiple keys at once.
285
+ Aside from that, the `:cached` options on collection rendering is available on Rails >= 6.0. This will cache the
286
+ rendered results effectively using the multi fetch feature.
287
+
288
+ ```ruby
289
+ json.array! @posts, partial: "posts/post", as: :post, cached: true
290
+
291
+ # or:
292
+ json.comments @post.comments, partial: "comments/comment", as: :comment, cached: true
293
+ ```
294
+
295
+ If your collection cache depends on multiple sources (try to avoid this to keep things simple), you can name all these dependencies as part of a block that returns an array:
296
+
297
+ ```ruby
298
+ json.array! @posts, partial: "posts/post", as: :post, cached: -> post { [post, current_user] }
299
+ ```
300
+
301
+ This will include both records as part of the cache key and updating either of them will expire the cache.
302
+
303
+ ## Formatting Keys
259
304
 
260
305
  Keys can be auto formatted using `key_format!`, this can be used to convert
261
306
  keynames from the standard ruby_format to camelCase:
@@ -274,6 +319,25 @@ environment.rb for example):
274
319
  Jbuilder.key_format camelize: :lower
275
320
  ```
276
321
 
322
+ By default, key format is not applied to keys of hashes that are
323
+ passed to methods like `set!`, `array!` or `merge!`. You can opt into
324
+ deeply transforming these as well:
325
+
326
+ ``` ruby
327
+ json.key_format! camelize: :lower
328
+ json.deep_format_keys!
329
+ json.settings([{some_value: "abc"}])
330
+
331
+ # => { "settings": [{ "someValue": "abc" }]}
332
+ ```
333
+
334
+ You can set this globally with the class method `deep_format_keys` (from inside your
335
+ environment.rb for example):
336
+
337
+ ``` ruby
338
+ Jbuilder.deep_format_keys true
339
+ ```
340
+
277
341
  ## Contributing to Jbuilder
278
342
 
279
343
  Jbuilder is the work of many contributors. You're encouraged to submit pull requests, propose
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require "bundler/setup"
2
2
  require "bundler/gem_tasks"
3
3
  require "rake/testtask"
4
4
 
5
- if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
5
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["CI"]
6
6
  require "appraisal/task"
7
7
  Appraisal::Task.new
8
8
  task default: :appraisal
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "mocha", require: false
7
+ gem "appraisal"
8
+ gem "rails", "~> 6.1.0"
9
+
10
+ gemspec path: "../"
@@ -5,6 +5,6 @@ source "https://rubygems.org"
5
5
  gem "rake"
6
6
  gem "mocha", require: false
7
7
  gem "appraisal"
8
- gem "rails", github: "rails/rails"
8
+ gem "rails", github: "rails/rails", branch: "main"
9
9
 
10
10
  gemspec path: "../"
data/jbuilder.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jbuilder'
3
- s.version = '2.11.1'
3
+ s.version = '2.11.5'
4
4
  s.authors = 'David Heinemeier Hansson'
5
5
  s.email = 'david@basecamp.com'
6
6
  s.summary = 'Create JSON structures via a Builder-style DSL'
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.required_ruby_version = '>= 2.2.2'
11
11
 
12
12
  s.add_dependency 'activesupport', '>= 5.0.0'
13
+ s.add_dependency 'actionview', '>= 5.0.0'
13
14
 
14
15
  if RUBY_ENGINE == 'rbx'
15
16
  s.add_development_dependency('racc')
@@ -19,4 +20,12 @@ Gem::Specification.new do |s|
19
20
 
20
21
  s.files = `git ls-files`.split("\n")
21
22
  s.test_files = `git ls-files -- test/*`.split("\n")
23
+
24
+ s.metadata = {
25
+ "bug_tracker_uri" => "https://github.com/rails/jbuilder/issues",
26
+ "changelog_uri" => "https://github.com/rails/jbuilder/releases/tag/v#{s.version}",
27
+ "mailing_list_uri" => "https://discuss.rubyonrails.org/c/rubyonrails-talk",
28
+ "source_code_uri" => "https://github.com/rails/jbuilder/tree/v#{s.version}",
29
+ "rubygems_mfa_required" => "true",
30
+ }
22
31
  end
@@ -30,7 +30,7 @@ class <%= controller_class_name %>Controller < ApplicationController
30
30
 
31
31
  respond_to do |format|
32
32
  if @<%= orm_instance.save %>
33
- format.html { redirect_to @<%= singular_table_name %>, notice: <%= %("#{human_name} was successfully created.") %> }
33
+ format.html { redirect_to <%= show_helper %>, notice: <%= %("#{human_name} was successfully created.") %> }
34
34
  format.json { render :show, status: :created, location: <%= "@#{singular_table_name}" %> }
35
35
  else
36
36
  format.html { render :new, status: :unprocessable_entity }
@@ -43,7 +43,7 @@ class <%= controller_class_name %>Controller < ApplicationController
43
43
  def update
44
44
  respond_to do |format|
45
45
  if @<%= orm_instance.update("#{singular_table_name}_params") %>
46
- format.html { redirect_to @<%= singular_table_name %>, notice: <%= %("#{human_name} was successfully updated.") %> }
46
+ format.html { redirect_to <%= show_helper %>, notice: <%= %("#{human_name} was successfully updated.") %> }
47
47
  format.json { render :show, status: :ok, location: <%= "@#{singular_table_name}" %> }
48
48
  else
49
49
  format.html { render :edit, status: :unprocessable_entity }
@@ -55,6 +55,7 @@ class <%= controller_class_name %>Controller < ApplicationController
55
55
  # DELETE <%= route_url %>/1 or <%= route_url %>/1.json
56
56
  def destroy
57
57
  @<%= orm_instance.destroy %>
58
+
58
59
  respond_to do |format|
59
60
  format.html { redirect_to <%= index_helper %>_url, notice: <%= %("#{human_name} was successfully destroyed.") %> }
60
61
  format.json { head :no_content }
@@ -0,0 +1,109 @@
1
+ require 'delegate'
2
+ require 'active_support/concern'
3
+ require 'action_view'
4
+
5
+ begin
6
+ require 'action_view/renderer/collection_renderer'
7
+ rescue LoadError
8
+ require 'action_view/renderer/partial_renderer'
9
+ end
10
+
11
+ class Jbuilder
12
+ module CollectionRenderable # :nodoc:
13
+ extend ActiveSupport::Concern
14
+
15
+ class_methods do
16
+ def supported?
17
+ superclass.private_method_defined?(:build_rendered_template) && self.superclass.private_method_defined?(:build_rendered_collection)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def build_rendered_template(content, template, layout = nil)
24
+ super(content || json.attributes!, template)
25
+ end
26
+
27
+ def build_rendered_collection(templates, _spacer)
28
+ json.merge!(templates.map(&:body))
29
+ end
30
+
31
+ def json
32
+ @options[:locals].fetch(:json)
33
+ end
34
+
35
+ class ScopedIterator < ::SimpleDelegator # :nodoc:
36
+ include Enumerable
37
+
38
+ def initialize(obj, scope)
39
+ super(obj)
40
+ @scope = scope
41
+ end
42
+
43
+ # Rails 6.0 support:
44
+ def each
45
+ return enum_for(:each) unless block_given?
46
+
47
+ __getobj__.each do |object|
48
+ @scope.call { yield(object) }
49
+ end
50
+ end
51
+
52
+ # Rails 6.1 support:
53
+ def each_with_info
54
+ return enum_for(:each_with_info) unless block_given?
55
+
56
+ __getobj__.each_with_info do |object, info|
57
+ @scope.call { yield(object, info) }
58
+ end
59
+ end
60
+ end
61
+
62
+ private_constant :ScopedIterator
63
+ end
64
+
65
+ if defined?(::ActionView::CollectionRenderer)
66
+ # Rails 6.1 support:
67
+ class CollectionRenderer < ::ActionView::CollectionRenderer # :nodoc:
68
+ include CollectionRenderable
69
+
70
+ def initialize(lookup_context, options, &scope)
71
+ super(lookup_context, options)
72
+ @scope = scope
73
+ end
74
+
75
+ private
76
+ def collection_with_template(view, template, layout, collection)
77
+ super(view, template, layout, ScopedIterator.new(collection, @scope))
78
+ end
79
+ end
80
+ else
81
+ # Rails 6.0 support:
82
+ class CollectionRenderer < ::ActionView::PartialRenderer # :nodoc:
83
+ include CollectionRenderable
84
+
85
+ def initialize(lookup_context, options, &scope)
86
+ super(lookup_context)
87
+ @options = options
88
+ @scope = scope
89
+ end
90
+
91
+ def render_collection_with_partial(collection, partial, context, block)
92
+ render(context, @options.merge(collection: collection, partial: partial), block)
93
+ end
94
+
95
+ private
96
+ def collection_without_template(view)
97
+ @collection = ScopedIterator.new(@collection, @scope)
98
+
99
+ super(view)
100
+ end
101
+
102
+ def collection_with_template(view, template)
103
+ @collection = ScopedIterator.new(@collection, @scope)
104
+
105
+ super(view, template)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,4 +1,5 @@
1
1
  require 'jbuilder/jbuilder'
2
+ require 'jbuilder/collection_renderer'
2
3
  require 'action_dispatch/http/mime_type'
3
4
  require 'active_support/cache'
4
5
 
@@ -15,6 +16,38 @@ class JbuilderTemplate < Jbuilder
15
16
  super(*args)
16
17
  end
17
18
 
19
+ # Generates JSON using the template specified with the `:partial` option. For example, the code below will render
20
+ # the file `views/comments/_comments.json.jbuilder`, and set a local variable comments with all this message's
21
+ # comments, which can be used inside the partial.
22
+ #
23
+ # Example:
24
+ #
25
+ # json.partial! 'comments/comments', comments: @message.comments
26
+ #
27
+ # There are multiple ways to generate a collection of elements as JSON, as ilustrated below:
28
+ #
29
+ # Example:
30
+ #
31
+ # json.array! @posts, partial: 'posts/post', as: :post
32
+ #
33
+ # # or:
34
+ # json.partial! 'posts/post', collection: @posts, as: :post
35
+ #
36
+ # # or:
37
+ # json.partial! partial: 'posts/post', collection: @posts, as: :post
38
+ #
39
+ # # or:
40
+ # json.comments @post.comments, partial: 'comments/comment', as: :comment
41
+ #
42
+ # Aside from that, the `:cached` options is available on Rails >= 6.0. This will cache the rendered results
43
+ # effectively using the multi fetch feature.
44
+ #
45
+ # Example:
46
+ #
47
+ # json.array! @posts, partial: "posts/post", as: :post, cached: true
48
+ #
49
+ # json.comments @post.comments, partial: "comments/comment", as: :comment, cached: true
50
+ #
18
51
  def partial!(*args)
19
52
  if args.one? && _is_active_model?(args.first)
20
53
  _render_active_model_partial args.first
@@ -104,11 +137,30 @@ class JbuilderTemplate < Jbuilder
104
137
  private
105
138
 
106
139
  def _render_partial_with_options(options)
107
- options.reverse_merge! locals: options.except(:partial, :as, :collection)
140
+ options.reverse_merge! locals: options.except(:partial, :as, :collection, :cached)
108
141
  options.reverse_merge! ::JbuilderTemplate.template_lookup_options
109
142
  as = options[:as]
110
143
 
111
- if as && options.key?(:collection)
144
+ if as && options.key?(:collection) && CollectionRenderer.supported?
145
+ collection = options.delete(:collection) || []
146
+ partial = options.delete(:partial)
147
+ options[:locals].merge!(json: self)
148
+
149
+ if options.has_key?(:layout)
150
+ raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering."
151
+ end
152
+
153
+ if options.has_key?(:spacer_template)
154
+ raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering."
155
+ end
156
+
157
+ results = CollectionRenderer
158
+ .new(@context.lookup_context, options) { |&block| _scope(&block) }
159
+ .render_collection_with_partial(collection, partial, @context, nil)
160
+
161
+ array! if results.respond_to?(:body) && results.body.nil?
162
+ elsif as && options.key?(:collection) && !CollectionRenderer.supported?
163
+ # For Rails <= 5.2:
112
164
  as = as.to_sym
113
165
  collection = options.delete(:collection)
114
166
  locals = options.delete(:locals)
@@ -162,12 +214,7 @@ class JbuilderTemplate < Jbuilder
162
214
 
163
215
  def _fragment_name_with_digest(key, options)
164
216
  if @context.respond_to?(:cache_fragment_name)
165
- # Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
166
- # should be used instead.
167
217
  @context.cache_fragment_name(key, **options)
168
- elsif @context.respond_to?(:fragment_name_with_digest)
169
- # Backwards compatibility for period of time when fragment_name_with_digest was made public.
170
- @context.fragment_name_with_digest(key)
171
218
  else
172
219
  key
173
220
  end
@@ -1,4 +1,4 @@
1
- require 'rails/railtie'
1
+ require 'rails'
2
2
  require 'jbuilder/jbuilder_template'
3
3
 
4
4
  class Jbuilder