Jason Galuten
Jason Galuten

Reputation: 1072

How to use jbuilder to render a view partial to a variable in the controller in Rails?

When certain actions are performed, I am sending a json message to the client using web sockets. I like to be able to use view helpers in the jbuilder file so that I can nicely format json data.

How would one go about getting view-ready json into a variable in the controller? The best I have come up with is to use render_to_string, which works, but returns a String, so I then have to do JSON.parse, which is a lot of wasted converting, right?

So I have this:

msg = JSON.parse(render_to_string('show'))

which renders show.json.jbuilder into json and then returns it as a string, which is then parsed back into json.

It works, but it feels so wrong!

Upvotes: 4

Views: 1474

Answers (1)

Ryan Romanchuk
Ryan Romanchuk

Reputation: 10869

I stumbled around for hours, and also doing things that are just wrong. I have two horrible hacks. First problem I had was trying to use jbuilder to construct json to be stored in a payload that was not in a MVC context, but in a sidekiq worker. Luckily, I only needed one representation so I essentially rebuilt the template in user.rb Redacted example shown below.

def to_builder
  Jbuilder.new do |user|
    user.external_id id
    user.username username
    user.full_name full_name
  end
end

And then used

to_user_hash = {}
to_user_hash["user"] = JSON.parse(user.to_builder.target!)

to store the json, incredibly idiotic.

Now even more insane, when I was using active_model_serializers I was using a sidekiq worker to render a live activities page via websockets and did the following.

class ActivityBroadcasterWorker < ApplicationWorker
  sidekiq_options queue: :low, retry: true, backtrace: true

  def perform(activity_id)
    view = ActionView::Base.new(ActionController::Base.view_paths)
    view.class_eval("include Rails.application.routes.url_helpers")
    view.extend ApplicationHelper

    if activity = PublicActivity::Activity.find_by_id(activity_id)
      template = view.render_activity(activity)
      ActionCable.server.broadcast('activity_channel', message: template)
    end
  end
end

Have you found any better solution to simply tell jbuilder here is my resource, and i want to render this view, or this view partial?

Upvotes: 1

Related Questions