How to assign html to variable in rails view - ruby-on-rails

in php twig template I could do:
{% set chunk %}
<div class="foo">
bar {{ another_var_or_helper }}
...
</div>
{% endset %}
{{ chunk }} {# displays div #}
in rails I can do it with render partial or <% chunk = '..' %>. But how to do "twig style"?

Use a Helper function.
module SomeModelNameHelper
def html_chunk
"<div class='foo'>Bar</div>".html_safe
end
end
Then in your view you can call it thusly:
<%= html_chunk %>

Related

How can I eliminate whitespace showing up above a w3.css sidebar?

I am building a website using Jekyll and the W3.CSS Framework. I have a sidebar for navigation on large screens which collapses on smaller screens. The problem occurs on large screens. When content in the main div scrolls, the sidebar doesn't scroll with it. This leaves a white rectangle on top of the sidebar where the page header normally would be (the header scrolls up with the content).
I would like for the sidebar to scroll along with the content, or somehow hide the empty space. So far I've tried using the w3-top class, which anchors the sidebar to the top of the screen but covers up the header. I tried wrapping the sidebar and content divs with another div, which had no effect. I tried changing the background color of the sidebar which also had no effect. Here is my page layout:
<div class="w3-container w3-sidebar w3-bar-block w3-collapse w3-theme-light" style="width:250px" id="site-toc">
<button class="w3-button w3-large w3-hide-large w3-right" onclick="w3_close()">×</button>
<h4>Contents</h4>
{% assign section = site.data.contents[page.category] %}
{% for article in section.articles %}
{% if article.url == page.url %}
{% assign cls = "w3-bar-item w3-button w3-theme-l1" %}
{% else %}
{% assign cls = "w3-bar-item w3-button" %}
{% endif %}
{{ article.link-text }}
{% endfor %}
</div>
<article class="w3-container w3-main w3-theme-light" style="margin-left:250px">
<header">
<button class="w3-button w3-large w3-hide-large" onclick="w3_open()">☰</button>
<h2 style="color:#fff">{{ page.title }}</h2>
</header>
<section class="w3-text-theme">
{% if page.image %}
<img src="{{page.image}}" alt="{{ page.alt-text }}" class="w3-image" style="float:left;margin-right:16px;">
{% endif %}
{{ content }}
</section>
</article>
Any suggestions on how to fix this? This is my first web project in a decade and my javascript skills are non-existent at this point.
I decided to ditch the collapsible sidebar and try a different approach. I used the w3 fluid grid inside of a w3-row, which solved the scrolling problem.
---
layout: default
---
<div class="w3-row w3-theme-light">
<div class="w3-col l3 w3-hide-small w3-hide-medium" id="site-toc">
<div class="w3-bar-block w3-container">
<h4>Contents</h4>
{% assign section = site.data.contents[page.category] %}
{% for article in section.articles %}
{% if article.url == page.url %}
{% assign cls = "w3-bar-item w3-button w3-theme-l1" %}
{% else %}
{% assign cls = "w3-bar-item w3-button" %}
{% endif %}
{{ article.link-text }}
{% endfor %}
</div>
</div>
<div class="w3-col l6 w3-border">
<div class="w3-container w3-text-theme">
{{ content }}
</div>
</div>
<div class="w3-col l3 w3-hide-small w3-hide-medium">
<p></p>
</div>
</div>

Klaviyo Form shows twice on homepage

I embedded a klaviyo form on shopify and it showed twice on the homepage of the shop I'm working on. I'm quite new to shopify development but know django and a little rails but still get confused on reading codes.
<div class="homepage-page {{ section.settings.homepage_page_color }}" data-section-id="{{ section.id }}" data-section-type="index-page">
<!-- form -->
<div id="shopify-section-1538847772051" class="shopify-section adjust--white">
<div class="klaviyo-form-LLvHeC"></div>
</div>
{% for block in section.blocks %}
<div class="wrapper">
<div class="grid">
{% case block.type %}
{% when 'page' %}
{% if block.settings.home_page_content != blank %}
{% assign page = pages[block.settings.home_page_content] %}
{% assign page_src = page.content | escape %}
{% if page_src contains '<img' %}
{% assign homepage_page_grid = 'one-whole' %}
{% else %}
{% assign homepage_page_grid = 'large--five-sixths push--large--one-twelfth' %}
{% endif %}
<div class="grid__item {{ homepage_page_grid }}">
{% if block.settings.home_page_show_title %}
<h4 class="home__subtitle">{{ page.title }}</h4>
{% endif %}
<div class="rte homepage-page__content">
{% unless page == blank or page.empty? %}
{{ page.content }}
{% else %}
{{ 'home_page.onboarding.no_content' | t }}
{% endunless %}
</div>
</div>
{% endif %}
{% when 'text' %}
<div class="grid__item large--five-sixths push--large--one-twelfth">
<div class="rte homepage-page__content">
{% if block.settings.home_page_richtext != blank %}
{{ block.settings.home_page_richtext }}
{% else %}
{{ 'home_page.onboarding.no_content' | t }}
{% endif %}
</div>
</div>
{% else %}
{% endcase %}
</div>
</div>
{% endfor %}
{% if section.blocks.size == 0 %}
<div class="wrapper">
<div class="grid">
<div class="grid__item">
<div class="rte homepage-page__content">
{{ 'home_page.onboarding.no_content' | t }}
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% schema %}
Which part of this piece of code is the one showing the second form?
This is the form on top
This is the form that I do not need which is near the footer
You have not added the full code for the section, but as you are adding it on homepage I am sure it is a dynamic section. You can read more about Sections and their types on Shopify Docs about Theme Sections.
In you particular scenario, it looks like you are using 2 different instances of same type of section. So for 2 instances, your section code is included and rendered twice, thus the multiple forms.
I don't know the exact use case, but you can fix it by adding another block type specifically for adding klaviyo form code or moving klaviyo form code in some other file included on homepage.
This code is included anytime that you are using that type of section. If you add another section of that type , you would see 3 forms.
<div id="shopify-section-1538847772051" class="shopify-section adjust--white">
<div class="klaviyo-form-LLvHeC"></div>
</div>
The solution is to move this code outside of the section, like in some code snippet or add it as a separate block so that it is only rendered where added.

How to display bootstrap carousel with 3 items per slide using Liquid Shopify

I am trying to create a bootstrap carousel that displays 3 items per slide using Liquid.
This is my sample code
<div class="item active">
{% for course in courses %}
{% if forloop.index >= 1 and forloop.index <= 3 %}
<div class="col-md-4">
{% include "courses/box", course: course %}
</div>
{% endif %}
{% endfor %}
</div>
<div class="item">
{% for course in courses %}
{% if forloop.index >= 4 and forloop.index <= 6 %}
<div class="col-md-4">
{% include "courses/box", course: course %}
</div>
{% endif %}
{% endfor %}
</div>
At the moment, this code works but it is not dynamic. I would have to repeat the code for each loop and this becomes difficult when there are lot of courses/items that needs to be displayed.
I am wondering how I can somehow increment the forloop so it only displays 3 items/courses per slide. Kindly let me know if you need more information or code samples.
There might be a better options but this is what I figured.
<div class="item active">
{% for course in courses %}
{%- assign module = forloop.index | modulo: 3 -%}
{%- if module == 1 -%}
{%- unless forloop.first -%}
<div class="item">
{% endunless %}
{%- endif -%}
<div class="col-md-4">
{% include "courses/box", course: course %}
</div>
{%- if module == 0 -%}
{%- unless forloop.last -%}
</div>
{%- endunless -%}
{%- endif -%}
{% endfor %}
</div>
To break it down.
I wrap the whole logic in the <div class="item active"> and close it at the bottom.
I loop all of the courses
I assign a module variable which returns the module of 3 from the current forloop.index. So if you are on 3,6,9 etc.. index it will return 0.
I check if the module is 1 and if it's not the first loop ( this is because we already create the <div class="item active"> and we don't need another one and the if will be true when you are on the 4th loop, 7th loop and so on, a.k.a the place we need to put a new <div class="item"> )
I add the <div class="col-md-4">{% include "courses/box", course: course %}</div>
Finally I check if the module is equal to 0 or if this is the last loop ( because if it's the last loop we will have two </div> at the end ) and add the closing <div>.

Define a parent template and extend it in ruby on rails 4 like it is done in twig with "extends"

In twig i can have a parent layout which defines some standard
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2011 by you.
{% endblock %}
</div>
</body>
</html>
and then have a child layout which override some or all the blocks
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ parent() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome on my awesome homepage.
</p>
{% endblock %}
how can i do something similar in Rails 4?I looked around a bit but didn't find it.
You can create a layout for each controller. news.html.erb for NewsController etc.
You can then use content_for?, yield and render to nest the controller specific layouts inside application.erb.html
Here's an example from official rails guides.
In app/views/layouts/application.html.erb:
<html>
<head>
<title><%= #page_title or "Page Title" %></title>
<%= stylesheet_link_tag "layout" %>
<style><%= yield :stylesheets %></style>
</head>
<body>
<div id="top_menu">Top menu items here</div>
<div id="menu">Menu items here</div>
<div id="content"><%= content_for?(:content) ? yield(:content) : yield %></div>
</body>
</html>
In app/views/layouts/news.html.erb:
<% content_for :stylesheets do %>
#top_menu {display: none}
#right_menu {float: right; background-color: yellow; color: black}
<% end %>
<% content_for :content do %>
<div id="right_menu">Right menu items here</div>
<%= content_for?(:news_content) ? yield(:news_content) : yield %>
<% end %>
<%= render template: "layouts/application" %>
Source: http://guides.rubyonrails.org/layouts_and_rendering.html#using-nested-layouts

Inheritance in Slim template language

With PHP using Twig I can do something like this:
layout.twig
<html>
<body>
{% block content %}{% endblock %}
</body>
</html>
form.twig
{% extends "layout.twig" %}
{% block content %}
<div class="form">{% block form %}{% endblock %}</div>
{% endblock %}
login.twig
{% extends form %}
{% block form %}
<form>
<input type="text" name="email" />
<input type="submit">
</form>
{% endblock %}
This way I have a layout for all pages, a layout for pages with forms and login page.
But with Slim I can specify only main layout that is parent for all templates:
layout.slim
html
body ==yield
and special layouts for every page on my site:
login.slim
div.form
form
input type="text" name="email"
input type="submit"
Is there a simple way to realize Twig-like inheritance with more than one level in Slim?
It looks that I found the solution for Slim with Sinatra:
layout.slim
html
body
== yield
form.slim
== slim :layout
div.form
== yield
login.slim
== slim :form
form
input type="text" name="email"
input type="submit"
I believe that in Rails it doesn't exist something like template inheritance, but I believe that it isn't necessary with yield and content_for methods.
For example, you can have a _form.html.slim layout:
.form
= yield
A _login.html.slim partial:
form
input type="text" name="email"
input type="submit"
And when you want to display a login with the form layout, you should do something like:
= render partial: "login", layout: "form"
login.html.slim
= render layout: 'form' do
form
input type="text" name="email"
input type="submit"

Resources