I am currently switching ActiveModelSeralizer to JBuilder for rendering jsons. I was wondering, with ActiveModelSeralizer I can do something like:
text_content = UserSeralizer.new(user, :root => false)
And receieve the json string in the variable called text_content. Now that I am switching away from ActiveModelSeralizer, is there anyway to do the above with JBuilder?
I have a view partial inside of app/view/api/v1/users/_user.json.jbuilder Is there anyway to render that partial into a variable?
Thanks
Yes, you can. Just use Jbuilder.encode method:
# somewhere in User model
def display_to_json
Jbuilder.encode do |json|
json.name name
json.location display_location
json.description description
json.work_experience work_experience
end
end
and use it:
<!-- somewhere in view, just for example -->
<div ng-init="user = <%= #user.display_to_json %>"></div>
Notice : The class name is Jbuilder, not JBuilder.
json = ActionController::Base.new.view_context.render(partial: "api/v1/users/user", locals: {user: #user})
"I have a view partial inside of app/view/api/v1/users/_user.json.jbuilder Is there anyway to render that partial into a variable?"
How about
json.partial! 'api/v1/users', users: #users.all
This will render the partial and create a new variable, users, with the contents #users.all
In the Controller I used
render json: whatever
Example:
In items_controller.rb (btw I used MongoDB):
def show
render json: #item
end
And http://localhost:3000/items/ he replies me with the JSON:
I have not used any views
Try this code:
text_content = json.(user, :id, :name, :published_at)
jbuilder Railscasts
jbuilder response as array
For Render you can use this code:
json.partial! 'api/v1/users', users: #users.all
json render for partial
Related
I have a problem with rendering array properly with JBuilder on Rails 6 (API only mode).
I basically have a list of registration plates, which I want to fetch via API request
My index view looks like this:
# frozen_string_literal: true
json.array! #registration_plates,
partial: 'registration_plates/registration_plate',
as: :registration_plate
My show view looks like:
# frozen_string_literal: true
json.partial! 'registration_plates/registration_plate',
registration_plate: #registration_plate
And finally partial _registration_plate.json.jbuilder is very simple:
# frozen_string_literal: true
json.id registration_plate.id
json.plate registration_plate.plate.to_s
I do get a normal response from server:
But instead of an array, I get the series of JSON objects
Did anyone have similar problem, or do you have any idea how to solve it?
Than you in advance.
EDIT
Also my controller is configured to render the jbuilder rather than json
# GET /registration_plates
def index
#registration_plates = RegistrationPlate.all
render #registration_plates
end
# GET /registration_plates/1
def show
render #registration_plate
end
And if I change the index action to look like
def index
#registration_plates = RegistrationPlate.all
render json: #registration_plates.to_json(only: %i[id plate])
end
i do get correct output, but then, I defy the sole purpose of jbuilder
update your index to remove render #registration_plates
# GET /registration_plates
def index
#registration_plates = RegistrationPlate.all
end
render #registration_plates renders _registration_plate.json.jbuilder directly without going into index.json.jbuilder
I have two controllers like this:
app/controllers/collection_controller.rb:
class CollectionController < ApplicationController
def create
#collection = Collection.new(name: params[:name])
#collection.save!
render #collection
end
end
And an inherited class:
app/controllers/enterprise/collection_controller.rb:
class Enterprise::CollectionController < ::CollectionController
def create
#collection = Collection.new(name: params[:name])
#collection.company = Company.find(params[:company])
#collection.save!
render #collection
end
end
I have two partials:
app/view/collections/_collection.json.jbuilder:
json.extract! collection, :title, :description
json.users do
json.partial! collection.user
end
app/view/collections/_user.json.jbuilder:
json.extract! user, :name, :surname
The problem is:
When I load Enterprise::CollectionController#create, I get missing template app/views/enterprise/collections/_collection ....
I want Enterprise::CollectionController to use app/view/collections/_collection.json.jbuilder instead of app/view/enterprise/collections/_collection.json.jbuilder.
I tried to do something like:
render #collection, partial: 'collections/collection', but I receive:
But I receive:
missing template for ... app/views/enterprise/users/_user ...
How can I solve this?
After you changed your render partial to
render #collection, partial: 'collections/collection'
you are not getting an error for collection partial. you are getting an error for user partial. You will have to change the way you are rendering user partial to
json.partial! "collections/user", user: collection.user
Update:
you can try append_view_path. So basically you will append to the default search locations
class Enterprise::CollectionController < ::CollectionController
before_filter :append_view_paths
def append_view_paths
append_view_path "app/views/collections"
end
end
So rails will search in app/views/enterprise/collections, app/views/shared, app/views/collections in order
You can also use prepend_view_path if you want rails to search in app/views/collections first
PS: I haven't tested this.
I'm using RABL as the foundation for a JSON API. I need to display both an object (#user) and a collection (#posts) in a template. Typically, this is no problem. #posts are a child of #user, so, I just do this:
object #user
attributes :id, :name
child :posts do |post|...
The problem is, I run #posts through a helper method (by_category) in the controller like so:
#user = User.find(params[:id])
#posts = #user.posts.by_category(params[:category])
By just fetching the posts as a child node, I don't apply the helper method – and I can't fetch posts by_category.
I'm wondering how to best approach this, and if there's a way to display both an object and a collection in the same RABL template?
Right from the documentation, you can include locals in partials like this example:
You can also pass in other instance variables to be used in your template as:
Rabl::Renderer.new('posts/show', #post, :locals => { :custom_title => "Hello world!" })
Then, in your template, you can use #custom_title as:
attribute :content
node(:title) { #custom_title }
This allows you to use something like:
Controller:
Rabl::Renderer.new('user/show', #user, :locals => { :posts_category => "examples" })
Partial:
attribute id
node(:posts) { |user| user.posts.by_category(#posts_category) }
In my Rails app I already have the following code:
<% %w(number_of_students edit_class_name tech_help).each do |modal| %>
<%= render "common/modals/#{modal}" %>
<% end %>
There will be a few more modals added into app/views/common/modals and instead of explicitly listing them out in the %w() I was wanting to loop through the common/modals directory and just render each file.
Here is what I came up with:
def render_modals
files = Dir.glob("#{Rails.root}/app/views/common/modals/*").collect { |file| File.basename(file, ".html.erb").sub("_", "") }.flatten
files.collect do |modal|
render partial: "common/modals/#{modal}"
end.join.html_safe
end
define a simple method in where is more appropriate (maybe app helper?) like this:
def modals
%w(number_of_students edit_class_name tech_help)
end
if you need these modals in a controller/model too, maybe you should define this method in an appropriate class? For example
class Modal
def self.types
%w(number_of_students edit_class_name tech_help)
end
end
Also, if you are rendering the templates often, then also define
def render_modals
modals.map do |modal| # Modals here should be the method that you just defined, example, Modal.types
render partial: "common/modals/#{modal}"
end.join
end
Ok so I have a helper method in the application controller:
def run_test(test_name)
#computation stuff
render :partial => test_name
end
And I call it like so in views:
<%= run_test("testpartial") %>
and it renders ok with only 1 (although... the render partial seems to be returning an array instead of just the partial content?), but if I put the run_test helper call in the view twice I get a double render error, which shouldn't be happening with partials.
Any ideas?
render in a controller versus render in a view are different methods. The controller eventually calls render on a view, but the controller's render method itself expects to be called only once. It looks like this:
# Check for double render errors and set the content_type after rendering.
def render(*args) #:nodoc:
raise ::AbstractController::DoubleRenderError if response_body
super
self.content_type ||= Mime[formats.first].to_s
response_body
end
Note how it raises if called more than once?
When you call helper_method you give the view a proxy to the controller's version of render, which is not intended to be used in the same way as ActionView's, which is, unlike the controller's, expected to be called repeated to render partials and whatnot.
Looks like in Rails 3.2 this just works:
# application_helper.rb
def render_my_partial
render "my_partial"
end
You could try using render_to_string method in the view helper
render_to_string :partial => test_name, :layout => false