Rails – Display object and a collection in RABL template - ruby-on-rails

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) }

Related

Accessing controller data in order to pass local variables for rendering a haml partial in a view

I am trying to render a partial within a view. I have the following code in my view which calls upon the haml document being rendered:
= render :partial => 'data_popups/events'
However I need to pass local variables so 'undefined local variable' is solved. The controller, which contains all of the data, is under dataPopupsController#events ... is there anyway to access the data so I can pass local variables to the partial? Any and all help is welcome. Cheers~
As long as the data is available in your outer view, you can pass it to a partial using the locals option. For instance, if this was on your home page, you could pass the data to the controller like this...
# app/controllers/pages_controller.rb
class PagesController < ApplicationController
def home
#data = Model.get_data
end
end
Then, in your view, pass that #data into your partial using the locals option of the render method:
# app/views/pages/home.html.erb
<%= render :partial => 'data_popups/events', :locals => { :data => #data } %>
Without seeing your controller code, here's a basic example of what you could do:
class UsersController < ApplicationController
def index
#data = User.get_data
end
end
# views/users/index.html.erb
<%= #data.some_method %>
<%= render 'data_popups/events', :locals => { :data => #data } %>
# views/data_popups/_events.html.erb
<%= data.some_other_method %>
Notice that when you pass #data as a local to 'data_popups/events', you now reference the local variable as data.

How to pass variable to render in controller method in Rails

I am trying to pass a variable to render like this:
def monitor
#peripheries = Periphery.where('periphery_type_name=?','monitor')
render 'index', type: 'Monitor'
end
Here i want to use 'type' variable inside index view which looks like that:
<%= render 'some_partial', periphery_type: type %>
which also render something. But i want to use that 'type' variable
There are two ways to pass variables between the controller and views:
Instance variables
def monitor
#peripheries = Periphery.where('periphery_type_name=?','monitor')
#type = 'Monitor'
render 'index'
end
Rails will export any of the instance variables belonging to the controller to the view context. So you can call #type in the view or any partial.
Locals
def monitor
#peripheries = Periphery.where('periphery_type_name=?','monitor')
render 'index', locals: { type: 'Monitor' }
end
Note that you need to pass a hash to the locals option. You also need to pass the local variable to partial views:
<%= render 'some_partial', locals: { periphery_type: type } %>
Using locals is often a good idea since it encourages decoupling and can make your partials more reusable.
You can use redirect_to some_path(params: params)
In the monitor method, you can pass the type variable to the index view e.g.
def monitor
#type = 'monitor'
#peripheries = Periphery.where('periphery_type_name = ?', #type)
render 'index'
end
and in your view
<%= render 'some_partial', locals: {periphery_type: #type}
(Note this is not a good way to set up the type variable, I would need a better understanding of the class to suggest how to set that variable.)

Rails: Using JBuilder views outside of the view context

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

Conditional JSON output for ActiveRecord Model (Rails 3)

I am using ActiveRecord's as_json integration with ActiveSupport::JSON to render custom output in my controllers. A basic setup I have in my model looks something like this:
def as_json(options = {})
{ :guid => id,
:title => title,
:body => body,
:date => created_at }
end
I want to take this setup a step further and show select information depending upon options passed. My question is, when I call respond_with #model_instance or render :json => #model_instance am I able to pass options that the options argument in as_json receives? If not, should I just create and convert a unique hash in my controller?
Seems like you could just call .as_json and pass in the options, no?
render :json => #mymodel.as_json(:someoption =>" value")

Rendering a collection of different classes in Rails

I have a collection that contains instances of several different classes, and I want to render the partial for each instance. I can do this using the following code:
<%= render #results %>
My question is: How can I render the different partials in a different base directory? The above code will look for app/views/stories/_story.html.erb, however, the partials for this action are all kept in a different directory - app/search/_story.html.erb. Is there any way of specifying this?
You could create a helper method like this:
def render_results(results)
result_templates = {"ClassA" => "search/story", "ClassB" => "something/else"}
results.each do |result|
if template = result_templates[result.class.name]
concat render(:partial => template, :object => result)
end
end
end
And then in the view call <% render_results(#results) %>
or you can use is_a?(Object)
if is_a?(classA)
render something_A
elsif is_a?(classB)
render something_B
end
I have a similar situation where I have multiple classes so I use a partial for each class like:
for result in #results
= render :partial => "result_#{result.class.to_s.downcase}", :locals => {:item => result}
end

Resources