Giter Site home page Giter Site logo

jbuilder's Introduction

Jbuilder

Jbuilder gives you a simple DSL for declaring JSON structures that beats manipulating giant hash structures. This is particularly helpful when the generation process is fraught with conditionals and loops. Here's a simple example:

# app/views/messages/show.json.jbuilder

json.content format_content(@message.content)
json.(@message, :created_at, :updated_at)

json.author do
  json.name @message.creator.name.familiar
  json.email_address @message.creator.email_address_with_name
  json.url url_for(@message.creator, format: :json)
end

if current_user.admin?
  json.visitors calculate_visitors(@message)
end

json.comments @message.comments, :content, :created_at

json.attachments @message.attachments do |attachment|
  json.filename attachment.filename
  json.url url_for(attachment)
end

This will build the following structure:

{
  "content": "<p>This is <i>serious</i> monkey business</p>",
  "created_at": "2011-10-29T20:45:28-05:00",
  "updated_at": "2011-10-29T20:45:28-05:00",

  "author": {
    "name": "David H.",
    "email_address": "'David Heinemeier Hansson' <[email protected]>",
    "url": "http://example.com/users/1-david.json"
  },

  "visitors": 15,

  "comments": [
    { "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
    { "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
  ],

  "attachments": [
    { "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
    { "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
  ]
}

To define attribute and structure names dynamically, use the set! method:

json.set! :author do
  json.set! :name, 'David'
end

# => {"author": { "name": "David" }}

To merge existing hash or array to current context:

hash = { author: { name: "David" } }
json.post do
  json.title "Merge HOWTO"
  json.merge! hash
end

# => "post": { "title": "Merge HOWTO", "author": { "name": "David" } }

Top level arrays can be handled directly. Useful for index and other collection actions.

# @comments = @post.comments

json.array! @comments do |comment|
  next if comment.marked_as_spam_by?(current_user)

  json.body comment.body
  json.author do
    json.first_name comment.author.first_name
    json.last_name comment.author.last_name
  end
end

# => [ { "body": "great post...", "author": { "first_name": "Joe", "last_name": "Bloe" }} ]

You can also extract attributes from array directly.

# @people = People.all

json.array! @people, :id, :name

# => [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ]

To make a plain array without keys, construct and pass in a standard Ruby array.

my_array = %w(David Jamie)

json.people my_array

# => "people": [ "David", "Jamie" ]

You don't always have or need a collection when building an array.

json.people do
  json.child! do
    json.id 1
    json.name 'David'
  end
  json.child! do
    json.id 2
    json.name 'Jamie'
  end
end

# => { "people": [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ] }

Jbuilder objects can be directly nested inside each other. Useful for composing objects.

class Person
  # ... Class Definition ... #
  def to_builder
    Jbuilder.new do |person|
      person.(self, :name, :age)
    end
  end
end

class Company
  # ... Class Definition ... #
  def to_builder
    Jbuilder.new do |company|
      company.name name
      company.president president.to_builder
    end
  end
end

company = Company.new('Doodle Corp', Person.new('John Stobs', 58))
company.to_builder.target!

# => {"name":"Doodle Corp","president":{"name":"John Stobs","age":58}}

You can either use Jbuilder stand-alone or directly as an ActionView template language. When required in Rails, you can create views ร  la show.json.jbuilder (the json is already yielded):

# Any helpers available to views are available to the builder
json.content format_content(@message.content)
json.(@message, :created_at, :updated_at)

json.author do
  json.name @message.creator.name.familiar
  json.email_address @message.creator.email_address_with_name
  json.url url_for(@message.creator, format: :json)
end

if current_user.admin?
  json.visitors calculate_visitors(@message)
end

You can use partials as well. The following will render the file views/comments/_comments.json.jbuilder, and set a local variable comments with all this message's comments, which you can use inside the partial.

json.partial! 'comments/comments', comments: @message.comments

It's also possible to render collections of partials:

json.array! @posts, partial: 'posts/post', as: :post

# or
json.partial! 'posts/post', collection: @posts, as: :post

# or
json.partial! partial: 'posts/post', collection: @posts, as: :post

# or
json.comments @post.comments, partial: 'comments/comment', as: :comment

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.

Be sure not to confuse the as: option to mean nesting of the partial. For example:

 # Use the default `views/comments/_comment.json.jbuilder`, putting @comment as the comment local variable.
 # Note, `comment` attributes are "inlined".
 json.partial! @comment, as: :comment

is quite different from:

 # comment attributes are nested under a "comment" property
json.comment do
  json.partial! "/comments/comment.json.jbuilder", comment: @comment
end

You can pass any objects into partial templates with or without :locals option.

json.partial! 'sub_template', locals: { user: user }

# or

json.partial! 'sub_template', user: user

You can explicitly make Jbuilder object return null if you want:

json.extract! @post, :id, :title, :content, :published_at
json.author do
  if @post.anonymous?
    json.null! # or json.nil!
  else
    json.first_name @post.author_first_name
    json.last_name @post.author_last_name
  end
end

To prevent Jbuilder from including null values in the output, you can use the ignore_nil! method:

json.ignore_nil!
json.foo nil
json.bar "bar"
# => { "bar": "bar" }

Caching

Fragment caching is supported, it uses Rails.cache and works like caching in HTML templates:

json.cache! ['v1', @person], expires_in: 10.minutes do
  json.extract! @person, :name, :age
end

You can also conditionally cache a block by using cache_if! like this:

json.cache_if! !admin?, ['v1', @person], expires_in: 10.minutes do
  json.extract! @person, :name, :age
end

Aside from that, the :cached options on collection rendering is available on Rails >= 6.0. This will cache the rendered results effectively using the multi fetch feature.

json.array! @posts, partial: "posts/post", as: :post, cached: true

# or:
json.comments @post.comments, partial: "comments/comment", as: :comment, cached: true

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:

json.array! @posts, partial: "posts/post", as: :post, cached: -> post { [post, current_user] }

This will include both records as part of the cache key and updating either of them will expire the cache.

Formatting Keys

Keys can be auto formatted using key_format!, this can be used to convert keynames from the standard ruby_format to camelCase:

json.key_format! camelize: :lower
json.first_name 'David'

# => { "firstName": "David" }

You can set this globally with the class method key_format (from inside your environment.rb for example):

Jbuilder.key_format camelize: :lower

By default, key format is not applied to keys of hashes that are passed to methods like set!, array! or merge!. You can opt into deeply transforming these as well:

json.key_format! camelize: :lower
json.deep_format_keys!
json.settings([{some_value: "abc"}])

# => { "settings": [{ "someValue": "abc" }]}

You can set this globally with the class method deep_format_keys (from inside your environment.rb for example):

Jbuilder.deep_format_keys true

Testing JBuilder Response body with RSpec

To test the response body of your controller spec, enable render_views in your RSpec context. This configuration renders the views in a controller test.

Contributing to Jbuilder

Jbuilder is the work of many contributors. You're encouraged to submit pull requests, propose features and discuss issues.

See CONTRIBUTING.

License

Jbuilder is released under the MIT License.

jbuilder's People

Contributors

amatsuda avatar asnow avatar bigjason avatar chrisxue815 avatar claudiob avatar dhh avatar eileencodes avatar georgeclaghorn avatar hparker avatar javan avatar jeremy avatar jmbejar avatar kaspth avatar maclover7 avatar masarufuruya avatar mvastola avatar nragaz avatar olleolleolle avatar pctj101 avatar petergoldstein avatar pixeltrix avatar rafaelfranca avatar rgarver avatar robin850 avatar rolftimmermans avatar rwz avatar spastorino avatar tenderlove avatar vincentwoo avatar yuki24 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jbuilder's Issues

Support for fragment caching helper

Functionality similar to the fragment caching helper method in erb templates - <%cache @key do%> <%end%>

Additionally, if the entire output of the JBuilder template is to be cached under one key the first line of the template can specify the key - cache @key

Method to return the Hash representation (for use with as_json)

It would be really useful to use JBuilder within an as_json method definition, as in the following pseudo code:

class Article < ActiveRecord::Base
  def as_json
    Jbuilder.hash do |json|
      json.(@article, :id, :name, :created_at)
      json.author @article.author.as_json
    end
  end
end

that would return a Hash object, rather than a JSON string.

This would allow nesting / use with other as_json calls etc...

Looking at the source code, it should a relatively straight forward to expose the @attributes?

TypeError when requiring jbuilder after cucumber

When you require jbuilder (0.4.0) after requiring cucumber (1.2.0), a TypeError is thrown. Start with the simple Ruby file:

require 'rubygems'
require 'cucumber'
require 'jbuilder'

Which produces:

$ ruby test.rb
/Users/nick/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/jbuilder-0.4.0/lib/jbuilder.rb:13:in `define_method': wrong argument type NilClass (expected Proc/Method) (TypeError)
    from /Users/nick/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/jbuilder-0.4.0/lib/jbuilder.rb:13:in `<class:Jbuilder>'
    from /Users/nick/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/jbuilder-0.4.0/lib/jbuilder.rb:7:in `<top (required)>'
    from /Users/nick/.rbenv/versions/1.9.3-p125/lib/ruby/1.9.1/rubygems/custom_require.rb:59:in `require'
    from /Users/nick/.rbenv/versions/1.9.3-p125/lib/ruby/1.9.1/rubygems/custom_require.rb:59:in `rescue in require'
    from /Users/nick/.rbenv/versions/1.9.3-p125/lib/ruby/1.9.1/rubygems/custom_require.rb:35:in `require'
    from test.rb:3:in `<main>'

Switching the order to require jbuilder before cucumber exits with no errors.

This is a particular problem if you are using jbuilder in a bundled project which also has cucumber in the Gemfile. Cucumber will be loaded first and when you require jbuilder, this exception is thrown.

Array issue

Hi by documentation you can create array like 'json.array!(collection) do | item | ....'. It doesn't work for me. I have to everytime use 'json.array!(collection) do | json, item | ...' and then It works. Is this correct way or am I doing something wrong?

Can I use yield in this jbuilder?

I want to make layout for my API json results.
This plugin is so simple... I like that!, but can I use yield so I can make a template for my API application? How..?

Thank You, :-)

Using .where doesn't work?

?So if I do @users = User.all then json.users @users, :first_name, :last_name, :auth_level everything works great. But if I do @users = User.where(auth_level: 7) then json.users @users, :first_name, :last_name, :auth_level I get:

ActionView::Template::Error (undefined local variable or method first_name' for #<ActiveRecord::Relation:0x007fceb40c2698>): app/views/v1/users/index.json.jbuilder:6:inblock in _app_views_v__users_index_json_jbuilder__979575319700469843_70262882566140'
app/views/v1/users/index.json.jbuilder:5:in `_app_views_v__users_index_json_jbuilder__979575319700469843_70262882566140'

Rendered /Users/cj/.rvm/gems/ruby-1.9.3-p0@global/gems/actionpack-3.1.3/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms)
Rendered /Users/cj/.rvm/gems/ruby-1.9.3-p0@global/gems/actionpack-3.1.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.4ms)
Rendered /Users/cj/.rvm/gems/ruby-1.9.3-p0@global/gems/actionpack-3.1.3/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (9.4ms)
Is this a known bug or am I doing something wrong?

Not returning a response body in JSON when testing RSPEC

Hi,

I'm having trouble getting a response.body content when using jbuilder.. I'm not sure if this is an issue with jbuilder or an issue with me.. any help would be much appreciated

When testing a JSON response from an RSPEC controller test using JBuilder, my response.body is always "{}". It works fine in development/production modes when requested in the browser AND when I use the to_json method instead of jbuilder, I get proper JSON in my response.body

Anyone have a clue as to why my response.body would always be "{}" when testing?

----- Rspec/Debugger -------

it "should return the cart items via JSON", :focus do

get :index, :format => :json
end

(rdb:1) response.body

"{}"

Can't nest unnamed array within named array

Okay let me try to explain my situation clearly, because its been driving me batty.

I have a model Product, with attributes: name, category, timestamps. I want to output a list of products, grouped by category.

@grouped_products = Product.all.group_by(&:category)

Assuming categories of "Software" and "Hardware", the structure I am trying to end up with is:

{
"hardware":[ {"name":"Amiga 500"}, {"name":"Apple IIc} ],
"software":[ {"name":"Wasteland"} ]
}

To do this, I would use the following jbuilder code (I intend on using partials but the following code is simpler to read):

@grouped_products.each do |category, products|
  json.set!(category) do
    json.array!(products) do |json, product|
      json.name product.name
    end
  end
end

But that doesn't work. Instead, the array! call dumps out the entire object and ignores what's in the block:

{
"hardware":[ {"name":"Amiga 500", "category":"hardware", "created_at":"2012-09-27T00:23:10Z", "updated_at"::"2012-09-27T00:23:10Z"},...
}

The only way I can actually get the results I want is to use a named array as follows:

@grouped_products.each do |category, products|
  json.set!(category) do
    json.products(products) do |json, product|
      json.name product.name
    end
  end
end

But that would give me an additional node I don't want:

{
"hardware":{"products":[{"name":"Amiga 500"}, {"name":"Apple IIc} ]},
"software":{"products":[ {"name":"Wasteland"}]}
}

What am I missing here?? Any help appreciated.

ActionView::DependencyTracker doesn't track jbuilder templates

Rails 4 doesn't dependency check jbuilder templates. This code (use as an initialiser, and is a minor edit of the supplied ERB tracker) adds a dependency tracker for jbuilder files to aid in russian doll caching strategies. Expect this will only work in Rails 4 (tested on Beta 1).

module ActionView
  class JBuilderTracker
    # Matches:
    #   json.partial! 'application/status'
    #   json.partial! @topic
    #   json.partial! topics
    #   json.partial! message.topics
    RENDER_DEPENDENCY = /
      partial!\s*                   # partial! call, followed by optional whitespace
      ([@a-z"'][@a-z_\/\."']+)      # the template name itself -- 1st capture
    /x

    def self.call(name, template)
      new(name, template).dependencies
    end

    def initialize(name, template)
      @name, @template = name, template
    end

    def dependencies
      Rails.logger.debug "Template Dependencies for #{name}: #{render_dependencies} + #{explicit_dependencies}"
      render_dependencies + explicit_dependencies
    end

  private
    attr_reader :name, :template

    def source
      template.source
    end

    def directory
      name.split("/")[0..-2].join("/")
    end

    def render_dependencies
      source.scan(RENDER_DEPENDENCY).
        collect(&:first).uniq.

        # partial! @topic           => "topics/topic"
        # partial! topics           => "topics/topic"
        # partial! message.topics   => "topics/topic"
        collect { |name| name.sub(/\A@?([a-z]+\.)*([a-z_]+)\z/) { "#{$2.pluralize}/#{$2.singularize}" } }.

        # partial! "headline"       => "message/headline"
        collect { |name| name.include?("/") ? name : "#{directory}/#{name}" }.

        # replace quotes from string renders
        collect { |name| name.gsub(/["']/, "") }
    end

    def explicit_dependencies
      source.scan(ActionView::DependencyTracker::ERBTracker::EXPLICIT_DEPENDENCY).flatten.uniq
    end
  end
end

ActiveSupport.on_load(:action_view) do
  ActiveSupport.on_load(:after_initialize) do
    require 'action_view/dependency_tracker'
    ActionView::DependencyTracker.register_tracker :jbuilder, ActionView::JBuilderTracker
  end
end

When using with Rails, nil is being sent to partials, causing "ActionView::Template::Error: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id "

This is easier to show than describe, but after updating Jbuilder from 0.4.3 to 0.8.2, we are seeing errors where an instance variable that's being used in a template tries to render partials, even when it's nil.

I'm unable to repeat this issue with straight Jbuilder - it's only happening when used with Rails as far as I can tell, so this may need to be fixed on the Rails side. Jbuilder is the only thing I'm changing to cause these, however.

I will try to come up with a broken example app later, but I'm stuck in meetings for awhile and wanted to report this before I forgot.

Example:

# user.json.jbuilder
json.(@user, :id, :name)

# @friends is nil
json.friends @friends do |json, friend|
  json.partial! :partial => 'users/friend', :locals => {:friend => friend}
end


# _friend.json.jbuilder
json.(friend, :id, :name)

Please update documentation for array

Hi rwz,

Thanks for this awesome gem! Great work!

When you have free time, could you please update the documentation for "array!".

Diff:
do |person| >> do |json, person|

(json is missing.)
On the Read me:

@people = People.all

json.array!(@people) do |person|
json.name person.name
json.age calculate_age(person.birthday)
end

On in the source:

json.array!(@people) do |json, person|

json.name person.name

json.age calculate_age(person.birthday)

end

Had some trouble with this until I read the source.

Thanks!

superclass mismatch for class Jbuilder

superclass mismatch for class Jbuilder

these error i found when I deployed to my vps ..I am using rails 3.2.11 ruby 1.87 on my local machine and ruby 1.9.3 on my vps server

currently broken iterating mongoid relations

The changes in commit cb1d566 on September 12 have broken iteration over relations in mongoid.

Specifically this code

collection.each.map do |element|
    _with_attributes { yield element }
end

in the method _map_collection because it assumes that the each method will return an iterator when it is not passed a block when mongoid in fact returns true. I suppose it would be fair to say that mongoid is to blame but it has been that way for some time and jbuilder appeared to be working with it before this commit.

Unable to use to_builder in arrays w/o naming return value

Seems if you use the to_builder syntax example, you must name the return value something when using to_builder within a to_builder.

Sometimes you don't want to name the return, but rather just get an array of unnamed return hashes.

See class Company below for 2 things that do not work:

# @people = People.all
json.array!(@people) do |person|
  json.name person.name
  json.age calculate_age(person.birthday)
end
# => [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ]
Jbuilder objects can be directly nested inside each other. Useful for composing objects.

class Person
  # ... Class Definition ... #
  def to_builder
    person = Jbuilder.new
    person.name self.name
    person.age self.age
    person
  end
end

class Company
  # ... Class Definition ... #
  def to_builder
    company = Jbuilder.new
    company.array!(@people) do |person|
        person.to_builder ### <<-- Case A) this is where it seems impossible to use #to_builder.  In this case because the json object isn't used, nothing appears in output

        json.person person.to_builder ### <<-- Case B)  in this case we force the name { person: { ... } }      
                                      ###  making it impossible to end up with [ { name, age }, {name, age} ]
                                      ###  forced to get: [ { person: { name, age }}, { person: {name, age}} ]
    end
    company
  end
end

company = Company.new("Doodle Corp", [ Person.new("John Stobs", 58), Person.new("John Stobs", 58) ])
company.to_builder.target!

Name Conflict with Existing Java IDE

This project shares a name with JBuilder which causes not only some confusion but cold sweats and heart palpitations for people who are allergic to Java.

It would probably be a good idea to employ an alternate name to avoid conflict in the form of a cease-and-desist notification in the future.

Support for JSON arrays without keys

I am building some JSON like this:

{
  "urls": [
    "http://example.com",
    "http://example.org"
  ]
}

Sorry for asking, but how do I build something like this with JBuilder? I have read the docs and examples, but it seems like they only focus on arrays with keys.

DSL question

Loving jbuilder, but I had a question. What is the reasoning behind the syntax of json.(@message, :created_at, :updated_at)? I like what it does but it's not so clear when reading.

JSONP Support

As this has some bearing with Javascript web applications, any plans on adding support for JSONP output?

Attempting to use set! with a jbuilder value gives odd results

I'm getting some very odd behavior when I attempt to use set! with a value that is a Jbuilder object and I don't include any sort of block. Depending on the context, I'm getting exceptions or corruption of the resulting JSON.

Consider the following expression:

Jbuilder.new do |json|
  child_builder = Jbuilder.new { |inner_json| inner_json.value 42}
  json.set! "test", child_builder
end.target!

I expect that this should yield:

"{\"test\":{\"value\":42}}"

Instead I'm getting

"{\"test\":{\"value\":42,\"is_a?\":{}}}"

The is_a? key appears to be a side effect of the is_a?(::Jbuilder) test in set! . As Jbuilder objects extend from ActiveSupport::ProxyObject (or ActiveSupport::BasicObject) they don't actually implement the is_a? method,

As far as I can tell, it's necessary to replace that is_a?(::Jbuilder) check in set! with something else - the question is exactly what. Does anyone have any thoughts on the cleanest solution here?

Display custom links above top level arrays using Jbuilder

I have a custom JSON response in which I display a collection of 15 posts along with related data like comments etc., as part of an API call. I am displaying the entire collection using Jbuilder .

json.array!(@posts) do |post|
..
..
end
I want to display pagination links above the json response of the 15 posts, in order to get the next set of posts with the appropriate next set of next page and prev page pagination links. In my abc.json.jbuilder file if I try doing it as per the below code, I don't get links to the next and prev page as part of my json response.

json.pagination_links do
json.set!(:next_page_link,"#{@next_page_link}")
json.set!(:prev_page_link,"#{@prev_page_link}")
end

json.array!(@posts) do |post|
..
..
end
The only response, that I get is the array which has a collection of posts. Which looks like below:-

[
-{post1}
-{post2}
-..
]
I guess there is something that I might be missing. Can anybody please suggest me any work arounds?

Thanks.

Release 1.1.0

We have some bugs fixed, and couple of new features added. Everything is 100% back-compatible, but new set! behavior calls for major version change according to SemVer.

feedback for new cache implementation

Hey,
just tested the new cache implementation, i get some weird behavior on my side (ruby 1.9.3p194, rails 3.2.2, memcached, jbuilder 0.7.0).

  # index.json.jbuilder
  json.cache! "users" do
    json.users @users do |json, user|
      json.id user.id
    end
  end

first request;

   {"users":[{"id": 68251 }]}

and the log:

  Cache read: jbuilder/users
  Cache generate: jbuilder/users
  Cache write: jbuilder/users
  Rendered users/index.json.jbuilder

all following requests:

   {}

and the log

  Cache read: jbuilder/users
  Cache fetch_hit: jbuilder/users
  Rendered location/users/index.json.jbuilder (0.7ms)

also, i had to add the blankslate gem to make it work. normal erb cashed fragment views are working fine.

json.partial! doesn't support :collection

When I do the following:

json.partial! "comment", :collection => comments

I expect this to be equivalent to

json.array!(comments) do |json, comment|
  json.partial! "comment", :comment => comment
end

Instead, jbuilder tries to render the partial once with collection as a local variable

Bad propagation of format with partial! when using render

I use a JBuilder template in a view to seed data to the Javascript side of the application.

To do so, I use a line like:

json = render(partial: 'users/user', formats: [:json], locals: { user: current_user })

Then, in my _user.json.jbuilder template, I have:

json.partial! 'vehicles/attribute', attribute: attribute

It doesn't work.

Due to the weird error reporting of JBuilder (see #40), I can't see the real reason but I managed to have the real error message (by creating a dumb _user.html.haml template):

Missing partial vehicles/attribute with {:locale=>[:fr], :formats=>[:html], :handlers=>[:erb, :builder, :jbuilder, :coffee, :haml]}.

As you can see, depsite the fact that I render the JSON version of my current_user template, JBuilder looks for the HTML version.

To get it working, I have to specify the format in the partial name:

json.partial! 'vehicles/attribute.json', attribute: attribute

But it provoques the deprecation warning:

DEPRECATION WARNING: Passing the format in the template name is deprecated. Please pass render with :formats => [:json] instead. (called from partial! at /home/foo/.rbenv/versions/1.9.3-p0/lib/ruby/gems/1.9.1/bundler/gems/jbuilder-e2a66168bfa3/lib/jbuilder_template.rb:18)

Note that passing a :formats option to partial! doesn't work neither.

Thanks!

Doubt about behavior change in f12791acf

Hello and thanks for this awesome gem.
I have a doubt regarding a change resulted by f12791a.

I have a RESTful controller for a Car model with two attributes: name and color and I have the following index.json.jbuilder to print all the cars:

json.cars @cars do |json, car|
  json.(car, :name)
  json.car do
    json.color car.color
  end
end

To print the name I use the inline syntax that allows to me to write multiple attributes on the same line; to print the color I use instead the block syntax.

The problem is that f12791a changed the output of the template above.

For brevity, imagine the database only includes one car with name: 'lamborghini' and color: 'yellow'. Before f12791a the output was:

{"cars"=>[{"name"=>"lamborghini", "color"=>"yellow", "car"=>{}}]}

After f12791a (that is, in the current master) the output is:

{"cars"=>[{"name"=>"lamborghini", "car"=>{"color"=>"yellow"}}]}

I'm not sure if this is a bug or the intended behavior because I couldn't find any test to support one choice or the other. Personally, I preferred the old result, because I could combine both inline and block syntaxes. Any opinion?

For the sake of clarity, I have also created a basic Rails repository that includes the example outlined above. If you run the specs (https://github.com/claudiob/jbuilder-question/blob/master/spec/controllers/cars_controller_spec.rb) you will see that they fail differently whether a version of jbuilder before or after f12791a is used. Thanks!

Readme

Hi!

in Readme,
is...

json.attachments @message.attachments do |attachment|

or...

json.attachments @message.attachments do |json, attachment|

?

Newest version 0.4.1 not on rubygems.org?

I just found out that the newest version of the gem is not yet available on rubygems.org. I'd need the new set! method of this commit: 7f1428b

It would be great to get the new version from rubygems.org :-)

Thanks in advance!

ArgumentError thrown when nesting attributes

In having a json response of {link:{href: "<address", method: "PUT"}} trying to map attributes to an element using nesting. The collision is occurring when you are including rake and jbuilder in the same gem file. Can easily recreate in IRB by performing the following:

$ irb
1.9.3p125 :001 > link
NameError: undefined local variable or method link' for main:Object from (irb):1 from /.rvm/rubies/ruby-1.9.3-p125/bin/irb:16:in

'
1.9.3p125 :002 > require 'rake'
=> true
1.9.3p125 :003 > link
ArgumentError: wrong number of arguments (1 for 2)
from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/fileutils.rb:306:in ln' from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/rake/file_utils_ext.rb:39:inlink'
from (irb):3
from /.rvm/rubies/ruby-1.9.3-p125/bin/irb:16:in <main>' 1.9.3p125 :004 > require 'jbuilder' => true 1.9.3p125 :005 > Jbuilder.encode do |json| 1.9.3p125 :006 > json.link 1, :href, :method 1.9.3p125 :007?> end WARNING: Global access to Rake DSL methods is deprecated. Please include ... Rake::DSL into classes and modules which use the Rake DSL methods. WARNING: DSL method #link called at /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:181:in_inline_extract'
ArgumentError: wrong number of arguments (1 for 2)
from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/fileutils.rb:306:in ln' from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/rake/file_utils_ext.rb:39:inlink'
from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/rake/dsl_definition.rb:165:in link' from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:181:in_inline_extract'
from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:145:in method_missing' from (irb):6:inblock in irb_binding'
from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:10:in block in encode' from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:10:intap'
from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:10:in encode' from (irb):5 from /.rvm/rubies/ruby-1.9.3-p125/bin/irb:16:in'
1.9.3p125 :008 > Jbuilder.encode do |json|
1.9.3p125 :009 > json.link 1, :href
1.9.3p125 :010?> end
WARNING: Global access to Rake DSL methods is deprecated. Please include
... Rake::DSL into classes and modules which use the Rake DSL methods.
WARNING: DSL method #link called at /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:181:in _inline_extract' ArgumentError: wrong number of arguments (1 for 2) from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/fileutils.rb:306:inln'
from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/rake/file_utils_ext.rb:39:in link' from /.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/rake/dsl_definition.rb:165:inlink'
from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:181:in _inline_extract' from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:145:inmethod_missing'
from (irb):9:in block in irb_binding' from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:10:inblock in encode'
from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:10:in tap' from /.rvm/gems/ruby-1.9.3-p125/gems/jbuilder-0.4.0/lib/jbuilder.rb:10:inencode'
from (irb):8
from /.rvm/rubies/ruby-1.9.3-p125/bin/irb:16:in `'

warning: undefining `object_id' may cause serious problems

Hi,

Since jbuilder 0.5.0 the following warning pops up when I $ bundle install or $ rails console:

/Users/sebastiaan/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/blankslate-3.1.2/lib/blankslate.rb:51: warning: undefining 'object_id' may cause serious problems

As you can see I'm running Ruby 1.9.3-p194.

This warning has been popping up since the bump to 0.5.0 so I thought it best to post an issue here instead of the blankslate repo. If I'm barking up the wrong tree let me know :)

Cheers,
Sebastiaan

Weird error reporting when an error occur in a JBuilder partial

Hi,

I noticed two errors in the reporting of errors with jbuilder partials rendered from a view.
The first is weird but not a big deal, the second is really problematic for debugging.

I have a view and two partials.

In views/application/home.html.haml, I have:

- json = render(partial: 'users/user', formats: [:json], locals: { user: @user })
= javascript_tag { "window.data = {}; window.data = #{raw(json)};" }

In views/users/_user.html.haml, I have:

= user.undefined_method_called_from_haml_template

In views/users/_user.json.jbuilder, I have:

json.name user.undefined_method_called_from_jbuilder_template

Displaying the page raises:

NoMethodError in Application#home
Showing ~/MyTest/app/views/users/_user.html.haml where line # raised:
undefined method `undefined_method_called_from_jbuilder_template' for #User:0x007fb2bea96de8

The reported file is wrong: it should be the JSON version.

So now, the second error is visible when there is no other version of the same partial (in my case, by removing _user.html.haml).

ActionView::MissingTemplate in Application#data
Showing ~/MyTest/app/views/application/home.html.haml where line #1 raised:
Missing partial users/user with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :jbuilder, :coffee, :haml]}.

What the hell? Why does any errors occurring in the partial are ignored and reported as a missing template (plus, the formats and handlers are not correct?
If I fix the error (not easy with this weird report) in the template, it works!

Any idea?

Error with jbuilder 0.8.2 : "missing attribute: photo_updated_at"

Hi,

After updating my Rails 3.1 to 3.2 i have this error in one of my jbuilder partial :

Failure/Error: get :show, :id => @user.to_param, :format => :json
ActionView::Template::Error:
missing attribute: photo_updated_at
# ./app/views/api/user_ipads/_user_ipad.json.builder:11:in block in _app_views_api_user_ipads__user_ipad_json_builder__4322258879011176669_70322613825420' # ./app/views/api/user_ipads/_user_ipad.json.builder:1:in_app_views_api_user_ipads__user_ipad_json_builder__4322258879011176669_70322613825420'
# ./app/views/api/user_ipads/show.json.jbuilder:1:in _app_views_api_user_ipads_show_json_jbuilder___1496169294239287635_70322552739840' # ./spec/controllers/api/user_ipads_controller_spec.rb:56:inblock (4 levels) in <top (required)>'

This is very strange since my model has the photo_updated_at column, and i can access it without problem outside the jbuilder partial. Here is the line that create the issue :

Line 11 : json.photo @user_ipad.photo.url

json.user_ipad do |json|
json.id @user_ipad.id
json.is_premium @user_ipad.is_premium
json.email @user_ipad.email
json.authentication_token @user_ipad.authentication_token
json.pseudo @user_ipad.pseudo
json.first_name @user_ipad.first_name
json.last_name @user_ipad.last_name
json.male @user_ipad.male
json.birthday @user_ipad.birthday
json.photo @user_ipad.photo.url

end

Do you have any idea where it could come from ?

Thanks,
Vincent

recursive partial! not working

Using ree 1.8.7 w/ jbuilder+patches from #4

Lets say we have a nested comment tree (think discussion forum)

Let say we have a file:

index.json.jbuilder

json.comments @comments do |json, comment|
json.partial! "example/comment", :comment => comment
end

Then we have _comment.json.jbilder

json.id comment.id
json.comment comment.text
json.replies comment.replies do |json, reply|
logger.info "Hello" # this prints
json.partial! "example/comment", :comment => reply # this is where we go "recursive"
logger.info "World" # program never makes it this far
end

Missing fields for nil

Keys with the value nil are not appearing in the generated JSON at all. The standard rails json used to output those with a value of null.

JBuilder returns blank responses in Cucumber tests

I've read about issues with RSpec and JBuilder, where config.render_views was false. My issue is with Cucumber and Rack::Test. Requests like this:

get "/users/1.json"

In my Cucumber steps return a blank response. Here is my app/views/users/show.json.jbuilder:

json.(@user, :id)

It is as simple as possible while I try and get any type of response. Removing the file renders @user correctly, but with it's as_json representation.

partial! not working in Jbuilder.encode block

When calling json.partial! inside a Jbuilder.encode block, the method does not render a partial, but is instead considered as a key for the output json.

Example:

json_string = Jbuilder.encode do |json|
  json.partial! 'path/to/my_partial'
end

Results in:

{'partial!': 'path/to/my_partial'}

If you try to pass any locals to the method, it complains:

json_string = Jbuilder.encode do |json|
  json.partial! 'path/to/my_partial', :user => current_user
end
TypeError:
{:user=>#<User id: 16, ...>} is not a symbol

Jbuilder rendering empty views

Trying to use Jbuilder to create some JSON views for my app, but the views are coming out empty.

Controller code:

@placements = Placement.all
respond_to do |format|
  format.html
  format.json
end

Jbuilder view (index.json.builder):

Jbuilder.encode do |json|
  json.array!(@placements) do |json, placement|
    json.id placement.id
    json.name placement.name
  end
end

Visiting http://localhost:3000/placements.json results in an empty page. Removing the respond_to format block doesn't help. If I use the following code in my controller, I get an output, but it's obviously not the Jbuilder output.

respond_to do |format|
  format.html
  format.json {render json: @placements}
end

Has anyone else seen this problem?

Specify custom partial

I am trying to use the partial! method to output nested relationships in a Rails app like so:

json.array!(@departments) do |json, department|
  json.partial! department
  json.jobs department.jobs  do |json, job|
    json.partial! job
  end
  json.staff department.users do |json, user|
    json.partial! 'app/views/staffs/staff', user
  end
end

My partial the staffs is actually calling the User model, but because of the way we are using routes, we have the views under staffs. Is there any way to a custom view path with a different name than the model being used, or does it have to be the same?

performance

My Rails application seems to be spending about 84% of the time rendering JBuilder views:

Completed 200 OK in 784ms (Views: 652.8ms | Mongo: 36.6ms)

All models are eager loaded and logs show only "Rendered ....json.jbuilder" partial lines

I've tried PerfTools + RubyProf to gain some insight but couldn't find specific problem - you can see attached results in the thread here https://groups.google.com/forum/?fromgroups#!topic/ruby-optimization/v6vSEravI5k

Suggestions? Anybody else experiencing this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.