What does “yield” do? - ruby-on-rails

What does yield do in ruby on rails?
<body data-spy="scroll" data-target=".sidebar">
<!-- Your timezone is <%= Time.zone %> -->
<!-- <%= "Ruby Version is #{RUBY_VERSION}" if Rails.env =~ /test|development/ %> -->
<%= render partial:'shared/account_status' %>
<%= render partial:"shared/session_timeout" %>
<div class="container">
<%= render partial:"shared/branding" %>
<%= render partial:"shared/nav", locals:{icons:icons, actionable_urls:actionable_urls, top_level_items:MenuItem.top_level_items_with_access_rights_for_user(current_user).sort{|a, b| a.sequence <=> b.sequence}, current_item:current_navigation_item} %>
<div style="clear:both"></div>
<div id="content">
<%= render partial:"shared/flash", object:flash %>
<%= yield %>
</div>
</div>
<%= render partial:"shared/ldap_user_menu" if signed_in_as_ldap_user? %>
</body>

It tells Rails to put your view content to this block (which is called by yield) at that place in the layout file.
Checkout the rails guide to learn more about the ActionView.
https://guides.rubyonrails.org/action_view_overview.html
As pointed out by #Aleksei Matiushkin, yield is pure ruby, so you should also learn more about that in your own time.
Here's a (my) visual presentation to explain what happened on that line:
view.html.erb:
<p>Hello there!</p>
<p>I'm a content from view</p>
layout.html.erb:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<%= yield %>
</body>
</html>
Now the results will be like this:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>Hello there!</p>
<p>I'm a content from view</p>
</body>
</html>

Your question is not specific enough. In Rails, as with ordinary Ruby, yield used within a method definition represents the block that is passed to a method.
However, judging from the code block that you gave, you seem to particularly want to ask about yield used in layouts of a view in Rails. In such case, it represents the main content described in the view file that is to be rendered in the context. For example, when the controller is Foo, and the action is bar, then, yield used within a layout to be used in such context will be replaced by the content of /app/views/foo/bar.html (or whatever corresponding view file in other format).

It must be simple in your concept: yield is where put content block (html) from action view to layout template
example: action index render index.html, the result will be put/filled in the yield

I haven't seen render mentioned in the other answers, so I'd like to add to #vipibano's answer, that if you want to understand how this yield business works in Rails (and more specifically in the application.html.erb), you'll benefit from:
understanding how blocks work in Ruby (as mentioned by others)
understanding what Rails' render method does
The render method is called at the end of a controller action and orchestrates what block is passed to the method that is actually rendering the application.html.erb.
I've tried to visualize this a bit and there a few examples if you want to dig deeper in the according post:
https://richstone.io/debunk/

Related

How to make rails reload only yield part?

I have a fixed header for every page on my rails app. Is there any way that when I click every link_to to whatever source only refresh the yield part?
<html>
<body>
<%= render 'layouts/header' %>
<div class="row">
<div>
<%= yield %>
</div>
</div>
The current code make each link refresh whole page including the header

Apitome sidebar disappears when included in a layout

I am using the rspec_api_documentation and apitome gems in a version 5.2 ruby on rails app.
This produces excellent documentation, and has a sidebar (div#sidebar) to allow quick access to the correct part of the documentation. When I choose the
config.layout = "layouts/application.html.erb"
option in the apitome.rb initializer, the documentation is rendered, but the sidebar has disappeared. Looking at the page source, the code for the sidebar is not being rendered, i.e. it is not a css problem, the html is not being put into the layout. To make sure it was not something unusual in my application.html.erb file, I simplified it to this
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<%= yield %>
</body>
</html>
This sidebar is very useful, so how do I render it in a layout?
Based on the response to this issue, I was able to solve this.
I created a new layout at app/views/layouts.apidocs.html.erb which rendered apitome/docs/navigation. A simple example would be as follows
# app/views/layouts/apidocs.html.erb
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4">
<div id="sidebar" class="sidebar hidden-print" role="complementary">
<%= render 'apitome/docs/navigation' %>
</div>
</div>
<div class="col-md-8" role="main">
<div class="docs-section">
<%= yield %>
</div>
</div>
</div>
</div>
</body>
</html>
I then configured this layout in the
apitome initialiser.
# config/initializers/apitome
Apitome.setup do |config|
...
config.layout = "layouts/apidocs.html.erb"
end
After some css tinkering, it all looked good.

How to conditionally add class to <body> in rails layout

My application.html.erb file looks like this
<!DOCTYPE html>
<html lang="en">
<head>
.
.
.
</head>
<body <%= "class=landing-bg" if !#landing.nil? %>>
<%= render 'layouts/header' %>
<div class="container">
.
.
.
</div>
<%= render 'layouts/footer' %>
<% if !#landing.nil? %>
<div class="landing-gradient"></div>
<% end %>
</body>
</html>
I've left out a bunch of meta tags in the <head> and a bunch of other code in the body that's unrelated to the question.
static_pages_controller
def home
#landing = "landing"
end
I need to add a class to <body> and a div below the footer only on my home page. I feel like what I am doing is a bit hacky. And, if I created a separate layout just for the landing page it wouldn't be DRY since I would be repeating alot of code that's on this layout.
What is the best way to do this? What is the rails way?
My typical pattern is to add the controller and action into the class of the body, and then use those as selectors in my css like this:
<body class="<%= controller_name %> <%= action_name %>">
<!-- etc -->
</body>
As for your second issue of a conditionally body on only the home page, you can simply add that into the body in the main layout and display it only on the landing page:
<body class="<%= controller_name %> <%= action_name %>">
<!-- etc -->
<div class="landing-gradient"></div>
</body>
# application.css
.landing-gradient {
display: none; // Hide the gradient
}
.landing .landing-gradient {
display: inline; // Show gradient b/c of more specific selector
}
This is my personal preference since you're leaving display of individual elements to the css / presentation layer instead of within your controllers.
Finally, you could also use a content_for around the footer so that you can customize the footer across individual pages. That's a bit heavy handed for your example though, so I'd only use that if you were customizing the footer a lot.
In my case I want to have a different class per layout (at least potentially), so in app/views/layouts/application.html.erb I do this:
<body class="<%= yield(:body_class) %>">
and then in my layout file I do this:
<% content_for(:body_class) { 'my-class' } %>
You can also manage it without creating an instance variable and verifying it in your view but using the params[:action] and params[:controller]:
<body class="<% 'class_value' if params[:controller] == 'static_pages' && params[:action] == 'home' %>"
You can just validate for the action (method) if you don't have more than one home method.

About some tags in rails program

i have got this program in ruby editor.My output comes out to be
<html>
<head><title> Ruby on Rails tutorial Sample App | <%= #title %></title>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
what is the error here and what is yield and csrf_meta_tag?
You don't seem to be using a server to render the views, it seems like you are rather loading the html directly on your browser.
Maybe the following link will help you get started:
http://guides.rubyonrails.org/getting_started.html
you need to rename your file from:
application.html to be application.html.erb so that it is going to interpret your embedded ruby commands.
Ref yield & content_for
Within the context of a layout, yield identifies a section where content from the view should be inserted. The simplest way to use this is to have a single yield, into which the entire contents of the view currently being rendered is inserted:
<html>
<head>
</head>
<body>
<%= yield %>
</body>
</html>
You can also create a layout with multiple yielding regions:
<html>
<head>
<%= yield :head %>
</head>
<body>
<%= yield %>
</body>
</html>
The main body of the view will always render into the unnamed yield. To render content into a named yield, you use the content_for method.

is it possible load a file.js.erb in <head></head>

I have a file.js.erb file in my views, but I need load this file in <head></head> layout.
Is it possible load these files in <head></head> section?
and if it's possible, How can I do it?
Thanks!
in your layout:
<head>
<script><%=render :file => "layouts/file.js"%></script>
</head>
If the file contains script tags then you wouldn't need them in the layout, and change the layouts in the path to wherever the file actually is.
If you don't want it on every page then you can use content_for and yield (as MyYorshiji suggests in the comments)
<head>
<script><%= yield :extra_js %> </script>
</head>
In the view html.erb where you want this js to load
<%content_for :extra_js do %>
<%=render :file => "layouts/file.js"%>
<% end %>
http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-content_for

Resources