I have a long code. For example:
<% Post.limit(10).offset(10).order(id: :desc).each do |post| %>
######## FROM HERE ###########
<% unless post.image.blank? %>
<% img = post.image.split(' ') %>
<% if post.post_type == 1 %>
<div class="post_type1">
<h1>
<a href="post/<%= post.slug %>">
<%= post.title %>
</a>
</h1>
</div>
<% end %>
<% end %>
####### TO HERE #########
<% end %>
So, I want to make this part(FROM HERE <-> TO HERE part) like a template. So I wrote first line, later render or something else, I do not know and the last line for displaying all the page. Can you help me with it?
Just put it in a file (lets call it _post.html.erb) and include it like:
<% Post.limit(10).offset(10).order(id: :desc).each do |post| %>
<%= render partial: 'post', locals: { post: post } %>
<% end %>
Note the use of locals: { post: post } that passes the variable post in your loop to your partial. Another thing to note is that your file name starts with an underscore (_) which is left out when you render the partial.
Read more about partials in Rails guide.
Related
Rails each do method is acting strangely and I do not know why.
controller
def index
#fabric_guides = FabricGuide.with_attached_image.all.order(:name)
end
index.html.erb
<div class="guide-items">
<%= #fabric_guides.each do |fabric| %>
<div class="guide-container">
<%= link_to fabric_guide_path(slug: fabric.slug) do %>
<%= image_tag fabric.image if fabric.image.attached? %>
<% end %>
<div class="guide-info">
<p class="g-name">
<%= link_to fabric.name,
fabric_guide_path(slug: fabric.slug) %>
</p>
</div>
</div>
<% end %>
</div>
I have two FabricGuide records so I expect two "guide-container" but I get three. Or more precisely I get two guide containers and a third block of text containing all the content from the last FabricGuide record.
I have almost an identical setup for articles and have never encountered this problem. I'd happily share more information if needed. Thank you!
Please remove = equal sign from your each loop of view code
like below :-
<% #fabric_guides.each do |fabric| %>
...
...
<% end %>
you have used this <%= #fabric_guides.each do |fabric| %> in your view that's why it shows all record in DOM.
The expression for erb tags is <% %>
now if we want to print that tag too then we apply <%= %>
I'm using the following code to display posts to my users.
_feed.html.erb partial:
<% #posts_by_month.each do |monthname, posts| %>
<%= monthname %>
<ul>
<% posts.each do |post| %>
<li><%= post.created_at %></li>
<% end %>
</ul>
<% end %>
Controller:
def home
if logged_in?
#post = current_user.posts.build
#posts_by_month = current_user.feed.group_by { |post| post.created_at.strftime("%B") }
This renders my posts as follows:
Post 1
Post 2
Post 3
Post 4
I want to change it so that the posts are displayed like:
Post 1 Post 2 Post 3
Post 4 etc etc
etc
I've tried several approaches to this, including the in_groups_of(3) method however the way it is currently setup means nothing works. I feel like there is an obvious solution I'm missing - can anyone help?
[Edit to expand on the in_groups_of(3) error]
If I change line 4 in the _feed partial to:
<% posts.in_groups_of(3, false).each do |post| %>
It gives the error: undefined method `created_at' for #< Array:0xbb8f258 >
The #in_groups_of method returns an Array of Arrays each containing 3 Post objects.
So you now also need to iterate over the returned array that contains your three Posts, something like:
<% posts.in_groups_of(3, false).each do |post_group| %>
<% post_group.each do |post| %>
<li><%= post.created_at %></li>
<% end %>
<% end %>
You can use facets gem. This provides and each_by method. You can use each_by to create groups and iterate further on these groups.
Here is code snippet on how to use each_by
<div class = "small-9 columns vertical-border-left">
<%- #client.contact_details.each_by(3) do |contact_details| %>
<div class="row">
<%- contact_details.each do |contact| %>
<div class="small-3 columns small">
<div> <%= contact.contact_detail_type %> contact </div>
<div> <%= contact.contact_email %> </div>
<div> <%= contact.contact_phone %> </div>
</div>
<% end %>
</div>
<% end %>
</div>
Is it possible to make small changes in different views?
The same partial is rendered in index.html.erb and show.html.erb as below.
index.html.erb
<%= render #schedules %>
show.html.erb
<%= render #schedules %>
What I'd like to do is not to display some value in the index.html.erb. (and display some value in both erb)
For example, I'd like to display start_at and end_at only in show.html.erb and display title in both erb.
_schedule.html.erb
<% schedule.rooms.each_with_index do |a, idx| %>
<% a.events.each do |e| %>
<%= l(e.start_at) %>-<%= l(e.end_at) %> # display only show.html.erb
<%= e.title %> #display both erb
...
<% end %>
...
<% end %>
Althogh I come up with idea which I create two partials, it contradicts the DRY policy.
It would be appreciated if you could give me any idea.
You can use controller.action_name.
<% if controller.action_name == 'show' %>
<%= l(e.start_at) %>-<%= l(e.end_at) %> # display only show.html.erb
<% end %>
The params hash also contains the action_name.
action_name is enough and do the trick but personally I don't like this. I'd do two separate partials.
Can check current action and current controller on page. So we can call single partial from different actions and can customize as per action name or action and controller name.
eg.
<% schedule.rooms.each_with_index do |a, idx| %>
<% a.events.each do |e| %>
<% if #current_controller == "events" and #current_action == "show" %>
<%= l(e.start_at) %>-<%= l(e.end_at) %> # display only show.html.erb
<% end %>
<%= e.title %> #display both erb
...
<% end %>
...
<% end %>
Also need to update Application Controller.
class ApplicationController < ActionController::Base
before_filter :instantiate_controller_and_action_names
def instantiate_controller_and_action_names
#current_controller = controller_name
#current_action = action_name
end
end
You could use CSS to hide/show the content based on context.
In practice, I have found this a good way to reuse partials that have small differences. Especially when those differences don't cost anything to compute i.e. printing a date
You can cache the partials without worrying about where they are rendered
Reduce conditional logic
Remove duplication
<% if controller.action_name == 'show' %> is fine for a simple use case. If/When you come to have multiple places where the partial needs to be rendered, it will become unwieldy. The CSS solution would only require another wrapper <div class="schedules--whatever"> and the related CSS style.
show.html.erb
<div class="schedules--show">
<%= render #schedules %>
</div>
index.html.erb
<div class="schedules--index">
<%= render #schedules %>
</div>
_schedule.html.erb
<% schedule.rooms.each_with_index do |a, idx| %>
<% a.events.each do |e| %>
<div class="event__date">
<%= l(e.start_at) %>-<%= l(e.end_at) %>
</div>
<%= e.title %>
...
<% end %>
...
<% end %>
schedules.css
.schedules--show .event__date {
display: block;
}
.schedules--index .event__date {
display: none;
}
How to make this code work?
<%= articles= Article.find_each
if articles
a.each do |a| %>
****some html****
<% end %>
<% end %>
right now it gives me an error:
no block given (yield)
It's hard to tell because your code is such a mess but i think you are trying to do this:
<% Article.all.each do |article| %>
<!-- some html - reference the local variable `article` in here, inside erb tags, eg -->
<div>
<%= article.name %>
</div>
<% end %>
EDIT: the above code will work fine (by which i mean happily generate no html at all) if there are no Article records in the db. Sometimes in this situation you might want to display some sort of extra info, like "You haven't created any Articles yet" or something. if this is the case you could do something like this:
<!-- typically this variable would be defined in the controller -->
<% #articles = Article.all %>
<% if #articles.blank? %>
<p>You haven't created any Articles yet</p>
<% else %>
<% Article.all.each do |article| %>
<!-- some html - reference the local variable `article` in here, inside erb tags, eg -->
<div>
<%= article.name %>
</div>
<% end %>
<% end %>
I have a very simple requirement - I have a layout comprising of a header and body. It is a sub-layout of the page, not for the page itself.
This layout is repeated throughout multiple pages, and it is possible the structure around it will change. So I want to be able to separate the content of the header and the content of the body from the structure that contains it.
My first attempt was to use render a partial as a layout that used named yields to render a header and body:
<header class="Resource-header">
<%= yield :resource_header %>
</header>
<div class="Resource-body">
<%= yield :resource_body %>
</div>
Then render it from my templates like this:
<%= render layout: 'admin/resource' do %>
<% content_for :resource_header do %>
<% end %>
<% content_for :resource_body do %>
<% end %>
<% end %>
However, this renders nothing.
I started playing with the order of things, and discovered that if the content_for blocks are declared before the call to the partial, this approach does work:
<% content_for :resource_header do %>
<% end %>
<% content_for :resource_body do %>
<% end %>
<%= render layout: 'admin/resource' do %><% end %>
However this just feels incredibly hacky. It seems that content_for is scoped globally, and there is no association between the content_for block and the partial rendering.
So what is the correct way for me to achieve this?
I just happened to have exactly same problem.
Solution is:
in your partial layout file 'admin/resource' body:
<header class="Resource-header">
<%= yield resource, :resource_header %>
</header>
<div class="Resource-body">
<%= yield resource, :resource_body %>
</div>
in your templates do:
<%= render layout: 'admin/resource' do |resource, section| %>
<% case section %>
<% when :resource_header %>
Resource header shows here.
<% when :resource_body %>
Resource body shows here.
<% end %>
<% end %>
Take a look on rails presenters https://www.ruby-toolbox.com/categories/rails_presenters
Maybe your solution is cells gem.
Eventhough the question is quite old now, I had a similar issue today. I came up with sth. like this. No gem or custom class required, just some fancy block usage ;)
<!-- app/views/layouts/fancy-blocks.html.erb -->
<%
body, footer = nil
yield(
proc {|&blk| body = capture(&blk) },
proc {|&blk| footer = capture(&blk) }
)
%>
<section class="body"><%= body %></section>
<footer><%= footer %></footer>
<!-- app/views/some-other/view.html.erb -->
<%= render 'layout/fancy-blocks' do |body, footer| %>
<% body.call do %>
BODY
<% end %>
<% footer.call do %>
FOOTER
<% end %>
<% end %>