Rendering a collection of different classes in Rails - ruby-on-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

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.

Rails: Loading in array of partials

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

HAML partials - partial does not recognized object which I queried for in the controller

I have this controller:
def index
#disclosures = Disclosure.where(:user_id => current_user.id)
respond_to do |format|
format.html{}
format.js{}
end
end
and with the help of the good folks at StackOverflow I am now able to get my HAML to point to the partial like this:
= render :partial => "/influencers/disclosures/shared/list"
but this partial throws and exception:
-if disclosures.empty?
.alert.alert-info
%p=(no_disclosures_message || (t "influencers.influencer_dashboard.disclosures.no_disclosures"))
%table.table.influencer-disclosures
%tbody
-disclosures.each do |disclosure|
=render "influencers/disclosures/shared/row", :disclosure => disclosure
saying that:
undefined local variable or method `disclosures' for #<#<Class:0x133ca8a58>:0x133ca25e0>
But how can this be? I just queried for that disclosures object in my controller. Any idea why this is happening and how to fix it?
Thanks!!
You need to put an # in front of disclosures. This is how the controller passes variables to the view.
-if #disclosures.empty?
and
-#disclosures.each do |disclosure|
Update
Another way to fix this is the change your render call. This will make it backwards compatible with other call sites of the same partial.
render :partial => "/influencers/disclosures/shared/list", :locals => {:disclosures => #disclosures}

Ruby on rails: Render 2 partials or figure out the kind of class and object is

I want to display different types of objects in the same ajax called controller function. I want to render out when I send back an ajax call. The problem is I want the "title" attribute of one object and the "name" attribute of another object. I can't render 2 partials and can seem to figure out how to check the type of object an object is. How do I solve this problem?
Here is my current controller setup (NOT CORRECT)
#objects = Obj.find(:all,:conditions => ["name Like ?", "#{prefix}%"])
#moreObjects = ObjTwo.find(:all,:conditions => ["title Like ?","#{prefix}%"])
if #objects.empty?
render :text => "No Matches"
else
render :partial => 'one', :collection => #objects
end
if #moreObjects.empty?
render :text => "No Matches"
else
render :partial => 'two', :collection => #moreObjects
end
try something like
<%= obj.title if obj.respond_to?(:title) %>
Here's one option that doesn't involve checking its type - in your Obj and ObjTwo classes add a new method:
def fancy_pants
title
end
def fancy_pants
name
end
Then you can combine #objects and #moreObjects - you'll only need one if statement and one partial.
#search_domination = #objects + #moreObjects
if #search_domination.empty?
render :text => "No Matches"
else
render :partial => 'one', :collection => #search_domination
end
You could use Object.is_a? but that's not a very clean solution. You could also try mapping your data before presentation to help keep your views lightweight.

Rails conditional ('if') statements based on controller action

There might be a better way to do this, but I'm trying to make an if statement in rails, based on the current action, in a controller (this will be used in a view).
For example, if its the edit page, or the show page, etc. I'd like a different style for something - is there an if statement that can specify this?
(I need an if statement, because its used in a partial, on multiple pages).
Thanks!
Elliot
The params hash that is available in the controller contains :controller and :action keys, which specify the controller and action names of the request.
Therefore you could say
if params[:action] == "foo"
# Show stuff for action 'foo'
elsif params[:action] == "bar"
# Show stuff for action 'bar'
elsif ...
# etc.
end
It's not good practice IMO to have partials asking what the current controller and action names are. Think "tell, don't ask" (http://www.pragprog.com/articles/tell-dont-ask). That is, rather than having the partial ask it's caller about its state, tell the partial what you want it to do.
One way to do this is by passing variables to the partial through the locals option:
<%= render :partial => "/common/toolbar", :locals => {:edit => true} %>
Then in the partial:
<% if defined?(edit) && edit %>
... stuff appropriate to edit mode
<% end %>
You can do it this way:
class ApplicationController < ActionController::Base
layout :set_layout
def set_layout
case params[:action]
when "foo"
"foo_layout"
when "bar"
"bar_layout"
...
else
"default_layout"
end
end
...
end
hope it helps =)
You can use layouts for partials too:
<%= render :partial => 'some_partial', :layout => 'wrap_with_stuff' %>
If you want to work out what layout to use dynamically I'd put that in a helper. So you'd end up with
# In your view
<%= render :partial => 'some_partial', :layout => layout_for_my_partial %>
# In your helper
def layout_for_my_partial
params[:action] == 'show' ? 'show_wrapper' : 'everything_else_wrapper'
end
This will only work in some circumstances, but might be what you're trying to do.
See more here.
http://ryandaigle.com/articles/2007/8/3/what-s-new-in-edge-rails-partials-get-layouts

Resources