Daniel Langer
Daniel Langer

Reputation: 106

How to Correctly render partial template in Rails?

I have a Listing model that I am using to represent a listing for a sublet (apartment), and I created a Filter model as a way for a user to filter listings to his liking. Here in my Filter class, that has a method listings to query listings based on a form submission.

class Filter < ActiveRecord::Base
  attr_accessible :air_conditioning, :available_rooms, :bathrooms, :furnished,  :negotiable, :new, :parking, :maximum_price, :private_bathroom, :show, :term, :total_rooms, :utilities, :washer_dryer
  serialize :term

  def listings
    @listings ||=find_listings
  end

private

  def find_listings
    listings=Listing.order(:price)
    listings=listings.where("listings.price <= ?", maximum_price) if maximum_price.present?
    listings=listings.where(total_rooms: total_rooms) if total_rooms.present?
    listings=listings.where(available_rooms: available_rooms) if available_rooms.present?
    listings=listings.where(bathrooms: bathrooms) if bathrooms.present?
    listings=listings.where(term: term)
    listings=listings.where(furnished: furnished)
    listings=listings.where(negotiable: negotiable)
    listings=listings.where(utilities: utilities)
    listings=listings.where(air_conditioning: air_conditioning)
    listings=listings.where(parking: parking)
    listings=listings.where(washer_dryer: washer_dryer)
    listings=listings.where(private_bathroom: private_bathroom)
    listings
  end

end

In order to show these, I created a show method for filter that I want to render a partial template. This is what I currently have, but it won't render the template I created called _listings.html.erb in /listings

<p id="notice"><%= notice %></p>

<%= @filter.listings.size %>

<%= render @filter.listings  %>

And here is the template

<div style="padding:5px">
<%= link_to 'New Listing', new_listing_path,{:style=>'', :class => "btn"} %>
<h1>Available Sublets</h1>

<table id="listingTable" class="table table-bordered table-hover">
  <tr>
    <th><%= link_to 'Filter', new_filter_path,{:style=>'', :class => "btn"} %><%= link_to 'Clear Filter', listings_path, {:style=>'', :class => "btn"} %></th>
    <th>Address</th>
    <th><u><%= "Price Per Month" %></u></th>
    <th>Description</th>
  </tr>
<% if @listings !=nil %>
    <% @listings.each do |listing| %>
      <tr onmouseover="this.style.cursor='pointer';"
      onclick="window.location.href = '<%= url_for(:controller => 'listings', :action => 'show', :id=>listing.id) %>' " >
        <td><%= image_tag listing.photo.url(:small) %></td>
        <td><%= listing.address %></td>
        <td>$<%= listing.price %></td>
        <td width="40%"><%= listing.description %></td>
      </tr>
    <% end %>
<% end %>
<% else if @listings==nil %>
    <p> Sorry, No Sublets Fit Your Criteria! </p>
<% end %>
</table>

I think my naming conventions are messed up, but I can't find the correct way to do this. Anyone have any suggestions. Also, the filter always seems to come up empty. I've tested it many times with simple filters but it never works. If anyone sees an error in my filter feel free to point it out. Thanks!

Upvotes: 0

Views: 1567

Answers (1)

Dan McClain
Dan McClain

Reputation: 11920

If you call render and pass it an array or relation, it will actually call the singular version on the partial. When you call

<%= render @filter.listings %>

What it ends up doing is equivalent the following:

<%= render :partial => 'listings/listing', :collection => @filter.listings %>

which is equivalent to

<% @filter.listings.each do |listing| %>
  <%= render listing %>
<% end %>

Also, there is an error in or partial around the `<% end %> <% else if ... %>, it should be the following

<% if @listings != nil %>
    <% @listings.each do |listing| %>
      <tr onmouseover="this.style.cursor='pointer';"
      onclick="window.location.href = '<%= url_for(:controller => 'listings', :action => 'show', :id=>listing.id) %>' " >
        <td><%= image_tag listing.photo.url(:small) %></td>
        <td><%= listing.address %></td>
        <td>$<%= listing.price %></td>
        <td width="40%"><%= listing.description %></td>
      </tr>
    <% end %>
<% else %> (since you already checked if it was nil, you it is implied at this point the value is nil
    <p> Sorry, No Sublets Fit Your Criteria! </p>
<% end %>

I would recommend writing it the following way, as it is more Ruby-esque

<% if @listings.blank? %>
    <p> Sorry, No Sublets Fit Your Criteria! </p>
<% else %>
     <% @listings.each do |listing| %>
      <tr onmouseover="this.style.cursor='pointer';"
      onclick="window.location.href = '<%= url_for(:controller => 'listings', :action => 'show', :id=>listing.id) %>' " >
        <td><%= image_tag listing.photo.url(:small) %></td>
        <td><%= listing.address %></td>
        <td>$<%= listing.price %></td>
        <td width="40%"><%= listing.description %></td>
      </tr>
    <% end %>
<% end %>

The way I would ultimately handle this case is the following:

Your Filter show view

<p id="notice"><%= notice %></p>

<%= @filter.listings.size %>
<div style="padding:5px">
<%= link_to 'New Listing', new_listing_path,{:style=>'', :class => "btn"} %>
<h1>Available Sublets</h1>

<table id="listingTable" class="table table-bordered table-hover">
  <tr>
    <th><%= link_to 'Filter', new_filter_path,{:style=>'', :class => "btn"} %><%= link_to 'Clear Filter', listings_path, {:style=>'', :class => "btn"} %></th>
    <th>Address</th>
    <th><u><%= "Price Per Month" %></u></th>
    <th>Description</th>
  </tr>
  <%= render(@filter.listings) ||  "<p> Sorry, No Sublets Fit Your Criteria! </p>".html_safe %>
</table>

Your 'listings/_listing.html.erb'

<tr onmouseover="this.style.cursor='pointer';"
  onclick="window.location.href = '<%= url_for(listing) %>' " >
  <td><%= image_tag listing.photo.url(:small) %></td>
  <td><%= listing.address %></td>
  <td>$<%= listing.price %></td>
  <td width="40%"><%= listing.description %></td>
</tr>

Upvotes: 1

Related Questions