5

In a Rails (5.2) app, I'm trying to use JBuilder to return some JSON as response.

I have added JBuilder in my Gemfile.

# Gemfile
...
gem 'jbuilder', '~> 2.5'
...

# Gemfile.lock
...
jbuilder (2.8.0)
...

According to JBuilder documentation:

You can also extract attributes from array directly.

@people = People.all

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

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

Now, in my controller, I have added the following:

def index
  respond_to do |format|
    format.json { render json.array! User.all, :email, :full_name }
  end
end

But I get

NameError - undefined local variable or method `json' for UsersController:0x00007fe2f966f150 16:55:40 rails.1
| => Did you mean? JSON:

Am I missing anything here?

Sig
  • 5,476
  • 10
  • 49
  • 89
  • 4
    You are kind of missing the entire point of using jBuilder in the first place which is to remove the concern of JSON rendering from the controller and move it into separate (view) layer. – max Jan 08 '19 at 11:57

2 Answers2

13

You typically use jbuilder in a view file with the extension .json.jbuilder

in your controller:

def index 
  @users = User.all
  respond_to do |format|
    format.json 
  end
end 

in your app/views/users/index.json.jbuilder

json.array! @users, :email, :full_name

EDIT: you can do it from the controller like that as well:

format.json { render json: Jbuilder.new { |json| json.array! User.all, :email, :full_name  }.target! }
Vincent Rolea
  • 1,601
  • 1
  • 15
  • 26
  • I understand that is the standard way. But, from the JBuilder documentation, it should be possible to return JSON directly from the controller. Isn't it? – Sig Jan 08 '19 at 10:21
  • I've gone through the documentation I don't see anywhere where it could be implied that it would be possible, as jbuilder has been built as a DSL to specifically avoid building hash structures in the controller. If you have simple data structures you want to render from the controller you can simply `format.json { render json: User.select(:email, :full_name) }` – Vincent Rolea Jan 08 '19 at 10:41
  • Actually you can do it from the controller, I've edited my answer – Vincent Rolea Jan 08 '19 at 10:45
  • 1
    To make it work I had to do `format.json { render json: Jbuilder.new { ... }.target! }` otherwise I get a `ActionView::MissingTemplate - Missing template` error. – Sig Jan 09 '19 at 03:58
2

You can do:

def index
  Jbuilder.new do |json|
    json.array! User.all, :email, :full_name
  end.attributes!
end

(It worked for me)

Source


Side note

You might see people doing:

Jbuilder.encode do |json|
 # ...
end

But Jbuilder.encode actually returns a string, as specified by this comment in the source code

Dharman
  • 30,962
  • 25
  • 85
  • 135
H. Almidan
  • 431
  • 4
  • 9