Some HTML for values of Hash keys - html

I am building a panel with a partial, but I'd like to customise the inside of the panel with some html. Is there any way to write some HTML for a hash value?
I have a custom partial _panel_builder.html.erb that I takes as argument pclass, heading, body, etc., that I would like to use like this :
(The below syntax is bad, but I don't really understand how I could do something nice..)
<% #etudes.each_with_index do |etude, i| %>
<%= render 'shared/panel_builder',
pclass: panel_color_rotation(i),
heading: etude.name,
# For the body param, I'd like to be able to use some HTML with occasional <%=...%> for variables, like :
body: (%>
<p><%=etude.description %></p>
<ul>
<%etude.competences.each do |comp| %>
<li><strong><%= competence.name %></strong> : <%=competence.level %>
<br><small><%=competence.why %></small>
</li>
<% end %>
</ul>
<%).html_safe,
collapsable: true %>
<% end %>
EDIT : An idea of what my _panel_builder partial looks like :
<%
collapsable ||= false
pclass ||= "default"
footer ||= false
%>
<div class="panel panel-<%= pclass %> <%= if collapsable then "panel-collapsable " end %>">
<div class="panel-heading">
<%= heading %>
<% if collapsable %>
<span class="pull-right"><i class="glyphicon glyphicon-chevron-down"></i></span>
<% end %>
</div>
<div class="panel-body <%= if collapsable then "collapse" end %>">
<%= body %>
</div>
<% if footer %>
<div class="panel-footer <%= if collapsable then "collapse" end %>">
<%= footer %>
</div>
<% end %>
</div>

Okay so I was actually looking for the capture helper :
<% #etudes.each_with_index do |etude, i| %>
<%= render 'shared/panel_builder',
pclass: panel_color_rotation(i),
heading: etude.name,
body: capture do %>
<p><%=etude.description %></p>
<ul>
<%etude.competences.each do |comp| %>
<li><strong><%= competence.name %></strong> : <%=competence.level %>
<br><small><%=competence.why %></small>
</li>
<% end %>
</ul>
<% end %>,
collapsible: true %>
<% end %>
Note : in some cases, I also want to pass a complex HTML block as the header of footer, so I can't just have a helper that takes a block.
Note2 : My panel is a HTML template made for generic data. I cannot pass it a Ruby object

Related

Rails use content_for and render the same layout twice

I am using a theme that has very specific layouts and I wanted to make a failsafe way to you rails forms.
I have a layout app/views/shared/forms/fields/_layout.html.erb
<div class="js-form-message mb-4">
<div class="js-focus-state input-group u-form">
<div class="input-group g-brd-primary--focus">
<%= yield(:field) %>
</div>
</div>
</div>
And I have two partials.
1-st partial: app/views/shared/forms/fields/_email.html.erb
<% form = locals[:form] %>
<% locals[:required] = locals[:required].nil? ? true : locals[:required] %>
<% locals[:placeholder] = locals[:placeholder] || t('forms.shared.email.placeholder') %>
<%= render layout: "shared/forms/fields/layout", locals: locals do %>
<% content_for(:field) do %>
<%= form.email_field :email,
placeholder: locals[:placeholder],
class: "form-control g-py-15 g-px-15",
"data-error-class"=>"u-has-error-v1-3",
"data-success-class"=>"u-has-success-v1-2",
"data-msg-email" => t('forms.shared.email.validate'),
"data-msg" => t('forms.shared.required'),
autofocus: locals[:autofocus],
required: locals[:required] %>
<% end %>
<% end %>
2-nd partial: app/views/shared/forms/fields/_login.html.erb
<% form = locals[:form] %>
<% locals[:required] = locals[:required].nil? ? true : locals[:required] %>
<% locals[:placeholder] = locals[:placeholder] || t('forms.shared.login.placeholder') %>
<%= render layout: "shared/forms/fields/layout", locals: locals do %>
<% content_for(:field) do %>
<%= form.email_field :login,
placeholder: locals[:placeholder],
class: "form-control g-py-15 g-px-15",
"data-error-class"=>"u-has-error-v1-3",
"data-success-class"=>"u-has-success-v1-2",
"data-msg" => t('forms.shared.required'),
autofocus: locals[:autofocus],
required: locals[:required] %>
<% end %>
<% end %>
And when I do this:
<%= render "shared/forms/fields/email", locals: {form: f} %>
<%= render "shared/forms/fields/login", locals: {form: f} %>
I get
Email Field
Email Field/Login Field
I found out that content_for 'appends' the block that you give it and then when I yield the whole block is returned.
The first time there is nothing in content_for(:field) and it appends to it Email Field. But the second time it does not clear its content and just appends Login Field to it.
I am thinking of adding additional complexity to layout.html.erb so just keeping it inline isn't an option.
Is there a way to tell to the layout only to yield the 'newest' value of content_for.
EDIT:
I wrote a method to flush after an yield, suggesting that the same key would be used again:
def yield_and_flush!(content_key)
view_flow.content.delete(content_key)
end
content_for has flush option to reset previous content:
<% content_for :field, flush: true do %>
new content here
<% end %>
The solution was this to write an yield_and_flush! method. I saw the solution here
def yield_and_flush!(content_key)
view_flow.content.delete(content_key)
end

Separating posts in a newsfeed using CSS/BootStrap

I'm currently trying to render a newsfeed, similar to that of FB on a Rails application I'm working on. Unfortunately, I'm not the greatest when it comes to CSS and I'm having some issues trying to display different posts. This issue occurs whether I'm using BootStrap or plain CSS. I do believe it's something to do with the loop that is created by <% #posts.each do |post| %> Currently, whenever a new post is made, it wraps inside the previous post; thus the more posts that are made, the thicker the border gets.
Image:
<% if #posts.any? %>
<% #posts.each do |post| %>
<div class="well">
<%= post.user.first_name %> <%= post.user.last_name %><br>
<% if !post.image.exists? %>
<h2> <%= post.text %> </h2>
<% else %>
<h2> <%= link_to post.text, post_path(post) %> </h2>
<%= link_to post_path(post) do %>
<p><%= image_tag post.image.url(:medium) %></p>
<% end %>
<% end %>
<% if #user %>
<% if current_user.voted_up_on?(post) %>
<%= link_to "Like", dislike_post_path(post), method: :put %>
<% else %>
<%= link_to "Like", like_post_path(post), method: :put %>
<% end %>
<% end %>
<%= "Likes: #{post.get_upvotes.size}" %>
<% if post.user == current_user %>
<%= link_to "Edit", edit_post_path(post) %>
<%= link_to "Delete", post_path(post), method: :delete %>
<% end %>
<div id='comments_div' class="comments-index">
<%= render post.comments %>
</div>
<% if current_user %>
<%= form_for [post, post.comments.new ], remote: true do |f| %>
<%= f.text_area :text, placeholder: 'Add a comment' %>
<%= f.submit 'Comment' %>
<% end %>
<% else%>
<p>You need to <%= link_to "sign in", new_user_session_path %> to comment</p>
<% end %>
<% end %>
<% else %>
No posts have been added!
<% end %>
</div>
Any help would be greatly appreciated! Thanks.
Edit: OK, please take a look at the new image -- hopefully that will make the issue slightly more obvious. Additionally, I've removed all the dead tags and replaced them with just one: BootStrap's 'well' class. So, there you have it. All the information you need is within the code above.
from your description it sounds as though an html element is not being properly closed. Run the page source through an html validator and that could show you the problem.
If you don't want to take a structured problem solving approach, try adding another </div> to the end of your posts-index container.
Your issue is very simple, just that its not clear due to poor indendation.
A simple way to explain what you did is:
<-- if (start) -->
<-- do (start) -->
<-- post (start) -->
(post is not ending here, hence it breaks the layout)
<-- do (end) -->
<-- if (end) -->
<-- post (end) -->
Mistake in the above should be simple to understand so if you move your last </div>(of the well class) just before the second last <% end %>(of the <% #posts.each do |post| %> loop) it should fix the issue. So the last few lines should be
<% else%>
<p>You need to <%= link_to "sign in", new_user_session_path %> to comment</p>
<% end %>
</div>
<% end %>
<% else %>
No posts have been added!
<% end %>
Sounds to me like it could be a misplaced
<% end %>
or a missing
</div>
that is causing this behavior.
Proper indentation will point to where to close off actions or divs

Import html to rails method (in helper.rb)

I need piece of code for couple of times, and to follow DRY method (don't repeat yourself) i want to escape using this piece and retyping it for 5 times or more. So I want to define method what will contain both ruby and html, and ruby in html and js to, code. But I have problems with realization.
My html.erb look like this:
<% div_count = 1 %>
<div>
<% for post in #posts %>
<div class="post-on-main-page-<%= div_count %>"
id="js-count-<%= div_count_for_js %>">
<script>
$("#js-count-<%= div_count_for_js %>").click(function(){
window.location.href = "<%= post_url(post) %>";
});
</script>
<%= image_tag(post.picture.url) %>
<span><h5><%= post.theme %></h5></span>
</div>
<% end %>
<% div_count += 1 %>
<% if div_count == 4 %>
<% div_count = 1 %>
<% end %>
</div>
And I want create method, I think in application_helper.rb will do with this piece of code. What will look something like that:
def method_name(parameter)
<% div_count = 1 %>
<div>
<% for post in parameter %>
<div class="post-on-main-page-<%= div_count %>"
id="js-count-<%= div_count_for_js %>">
<script>
$("#js-count-<%= div_count_for_js %>").click(function(){
window.location.href = "<%= post_url(post) %>";
});
</script>
<%= image_tag(post.picture.url) %>
<span><h5><%= post.theme %></h5></span>
</div>
<% end %>
<% div_count += 1 %>
<% if div_count == 4 %>
<% div_count = 1 %>
<% end %>
</div>
end
The result what I want for html.erb
<%= method_name(#posts)%>
How can I make this to work?
You can move this code to some html. And when you want to use it, you just call render method.
<%= render 'html_file' %>

Rails simple-form with multiple instances of the same object

I am trying to create a rails form using simple form that uses nested resources. However, I want to be able to submit multiple instances of the associated resource. Example below will probably explain it better.
<div class="tab-pane active" id="reminder">
<%= simple_form_for #collection, html: {multipart: true}, url: collection_index_path do |m| %>
<%= render partial: "collection/tabs/reminder", locals: { :m => m } %>
</div>
-inside partial
<% 9.times do |j|%>
<div class="tab-pane" id="<%= j %>">
<%= m.simple_fields_for :reminder do |p| %>
<%= p.input :heading %>
<%= p.input :message %>
<% end %>
</div>
There is a tabbed pane in which the user can click through 9 tabs to set up to 9 reminders, all should be associated with a collection (collection model accepts nested attributes for reminder). However, the way I have it setup now, the controller only gets what was set in the last reminder in the params. Anyway ideas would be appreciated.
There must be some way to distinguish tabs before submitting to controller. And i think answer might be here.
i.e. it looks like this:
<% 9.times do |j|%>
<div class="tab-pane" id="<%= j %>">
<%= m.simple_fields_for :reminders do |p| %>
<%= p.input :heading %>
<%= p.input :message %>
<% end %>
</div>
<% end %>

Ruby localization

I have to localize a web site, everything is almost done, except I have ran into two problems. The code below is for a small input form, but where are the strings? There is a label for a text field and a button.
Secondly, I am receiving an error:
"undefined method `-' for "translation missing: lv.date.order":String".
Where do i have to create the translation? In the .yml file? If so, how?
Thanks in advance!
<%= form_for([:admin, #publisher]) do |f| %>
<% if #publisher.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#publisher.errors.count, t(:error)) %> <%=t(:prohibited_saved)%></h2>
<ul>
<% #publisher.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This error means that Rails cannot find the translation for date.order in current locale file.
You should have a lv.yml file inside config/locales with this content:
lv:
date:
order:
- :day
- :month
- :year
It will instruct rails to show dates in a format: day/month/year