How to group and dry common view code in Rails - ruby-on-rails

I have two models Episode and Playlist with the following two views:
For Episode:
<div class="name">
<%= link_to episode.name, episode_path(episode) %>
</div>
<div class="description">
<%= link_to episode.description episode_path(episode) %>
</div>
For Playlist:
<div class="name">
<%= link_to playlist.name, playlist_path(playlist) %>
</div>
<div class="description">
<span>Some special span</span>
<%= raw(playlist.description) %>
</div>
The common things between this two views are the
<div class="name">. <div class="description">
but the content of this two divss is different for each view.
Question: How could I extract this two common divs into another view, called _section?
What have I tried:
Cells -> they give me a nice view model with properties, but I could not find a way to added additional HTML elements between the places where the properties will be put.
Yield and Content_for-> I have tried to create a separate _section layout with:
_section.html.erb
<div class="name">
<%= yield :name %>
</div>
<div class="description">
<%= yield :description %>
</div>
and then two views. The Episode view will render the following
<% render layout: "section" do %>
<% content_for :name do %>
<%= link_to episode.name, episode_path(episode) %>
<% end %>
<% content_for :description do %>
<%= link_to episode.description episode_path(episode) %>
<% end %>
<% end %>
This kind of works until you get to caching (they said content_for does not work with caching and I need to cache this) and the other problem I had was that you should include an additional empty not named yield.

I ended up with moving all the logic for playlist and episode views into a single view - called section that basically does the following:
<div class="name">
<%= link_to object.name, polymorphic_path(object) %>
</div>
<div class="description">
<% if is_episode? %>
<h1>Some special h1 for episode</h1>
<% elsif is_playlist? %>
<h2>Some special other html for playlist for episode</h2>
<% end %>
<%= raw(playlist.description) %>
</div>
Wow those "ifs" are ugly. I am not sure if I understood the problem correctly, but it is surprising I could not find a cleaner solution.

Related

How to pass an instance variable into a view partial?

Right now I have a loop that contains code I do not wish to repeat for each instance variable. I wish to put this in a partial and reuse it by changing the #new_posts instance variable, so I can use the same template for #featured_posts and #recommended_posts that I have defined.
I'm thinking of something like this:
<%= render "posts", posts: #featured_posts %>
An example of a loop that I wish to store in a partial
<% #new_posts.each do |post| %>
<div class="col-sm-4">
<div class="thumbnail">
<img src="#">
<div class="caption">
<h4><%= link_to post.title, post %></h4>
<%= post.text.truncate_words(60, omission: '...') %>
Button
</div>
</div>
</div>
<% end %>
How should I approach this? Thanks for your help!
Assign whatever variable you want to posts
<%= render "posts", posts: #featured_posts %>
And now loop over posts in the partial. You will have #featured_posts in posts variable now
<% posts.each do |post| %>
<div class="col-sm-4">
<div class="thumbnail">
<img src="#">
<div class="caption">
<h4><%= link_to post.title, post %></h4>
<%= post.text.truncate_words(60, omission: '...') %>
Button
</div>
</div>
</div>
<% end %>
For #recommended_posts render the same partial but pass #recommended_posts to posts
<%= render "posts", posts: #recommended_posts %>

Rails 4 - Multiple yield blocks on a partial

Is it possible to have a partial using more than one yield block? I wanted to use it to implement bootstrap modal boxes on my project, kinda like this:
<div class="modal fade" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<%= yield :header %>
</div>
<div class="modal-body">
<%= yield :body %>
</div>
<div class="modal-footer">
<%= yield :footer %>
</div>
</div>
</div>
</div>
And this is more or less how I was thinking of using it
<%= render partial: "shared/modal" do %>
<% content_for :header do %>
...
<% end %> %>
<% content_for :body do %>
...
<% end %> %>
<% content_for :footer do %>
...
<% end %> %>
<% end %>
Is there a way to do this? Is this maybe a bad approach for some reason?
Through much trial and error, I think I solved this in Rails 5 but needed to insert a blank yield in my partial in order to get it to work:
_partial.html.erb
<div class="partial">
<%= yield %> <!--Does not do anything-->
<div class="header">
<%= yield :header %>
</div>
<div class="text">
<%= yield :text %>
</div>
</div>
Implemented as:
full_layout.html.erb
<%= render "partial" do %>
<% content_for :header do %>
<h1>Header content</h1>
<% end %>
<% content_for :text do %>
<p>Text content</p>
<% end %>
<% end %>
I think you have an issue with your render partial. Notice you have all of your content_for blocks within the render partial block.
<%= content_for :thing do %>
Some content
<% end %>
<%= render partial: "blah" %>
It's no problem to use multiple yield blocks in your partial. Only thing is to make sure that many is actually needed. For an example content_for sections are basically placeholders for content that could vary based on the logic of the application. So, it's totally fine to use multiple yields in one page.
You can also just run put an yield there withouth the output. This way you can also use the default block.
<div>
<% yield %>
<div class="mt-3">
<div class="text-2xl tracking-wide font-bold text-gray-900">
heading
<%= yield :heading %>
</div>
</div>
<div class="relative bg-white rounded-xl shadow-xl mb-8 min-h-28">
<%= yield %>
</div>
...

Ruby on Rails View Rendering DB Info On Page

I am working on a project and currently working on one of the views which is a page of different categories. Everything is rendering correctly however it's also putting the db info in the page.
Here is the code of my view
<div class="categories">
<div class="container blurbs">
<div class="cards row">
<%= #categories.each do |c| %>
<div class="card col-xs-4" %>
<%= image_tag c.image, :class => "cat" %>
<h4 class="title"><%= c.title %></h4>
</div>
<% end %>
</div>
</div>
</div>
Here is a link to a
screenshot of rendered page
Yes, fix is:
<div class="categories">
<div class="container blurbs">
<div class="cards row">
<% #categories.each do |c| %>
<div class="card col-xs-4" %>
<%= image_tag c.image, :class => "cat" %>
<h4 class="title"><%= c.title %></h4>
</div>
<% end %>
</div>
</div>
</div>
Look I removed = from this <%=.. In the below line :
<% #categories.each do |c| %>
#each method returns the collection after it completed its iterations. And due to this <%=, the return value of each which is #categories printed back. But if you use <%.. only, all above things will happen, but it wouldn't print back the object #categories.
when you use the tags <%= ... %> whatever is within the tags gets displayed on the page. In your current view you have
<%= #categories.each do |c| %>
<div class="card col-xs-4" %>
<%= image_tag c.image, :class => "cat" %>
<h4 class="title"><%= c.title %></h4>
</div>
<% end %>
Which displays the entirety of whatever the loop returns which is where you're getting the display. Change the tags to be <% #categories.each do |c| %> and you'll be good to go.

link_to tag not including all divs

I currently have a link to tag which should wrap around all the content within it, but currently it's not doing that. It's wrapping around the code until it hits another div with a rails query inside it?
index.html.erb
<% #posts.each do |post| %>
<div class="widget" >
<%= link_to post do %>
<div class="image b-lazy" data-src="<%= post.image %>">
</div>
<div class="caption">
<h4><%= post.title %></h4>
<p>by <%= post.affiliate %></p>
</div>
<!-- LINK TO TAG ENDS HERE FOR SOME REASON -->
<div class="caption-top">
<% post.categories.each do |category| %>
<%= link_to category_path(category) do %>
<div class="tag <%= category.name %>"><%= category.name %></div>
<% end %>
<% end %>
</div>
<% end %>
</div>
Any help is appreciated!
Jonathan
Two things:
You are using link_to inside another call to link_to. That is probably not what you want.
The result of a block will be what you return from a block, normally the last line. Take a look at this question for a solution.

Jquery mobile, rails, collapsibles - extra labels appearing

I'm trying to display a simple collapsible set from a rails app. It works perfectly the first time, giving me the output below.
However, when I go back to the page (via the "Save changes" form submit), additional labels are appearing, and I can't work out why:
My index.html.erb file is as follows:
<div data-role="page" data-url="<%= request.path %>">
<div data-role="header">
<h1> CB </h1>
</div>
<div data-role="content">
<div data-role="collapsible-set">
<% #gr.each do |g| %>
<div id=" <%= g %>" data-role="collapsible">
<h3> <%= g %> </h3>
<p>
<%=form_tag "/checkboxen", method: :get do %>
<% #gr2.each do |g2| %>
<%= check_box_tag "#{g}_#{g2}" %>
<%= label_tag "#{g}_#{g2}",g2 %>
<% end %>
<%= submit_tag %>
<% end %>
</p>
</div>
<% end %>
</div>
</div>
While my (very simple) checkboxen_controller.rb is this:
class CheckboxenController < ApplicationController
def index
#gr=["one","two","three"]
#gr2=["a","b","c"]
end
end
As you can probably guess, I'm a newbie to this, and can't work out why it's happening (if it matters, I've turned turbolinks off, and have no unusual javascript in the system).
I've found a work-around: instead of using <%= label_tag %> I explicitly enclosed the check_box_tag in a <label> ... </label>. Why the original didn't work is something I still haven't figured out.

Resources