I have read it from the Rails guides, Have looked at Micheal Hartel book and now reading it from Rails View book but still I get confused :(
There is a _footer.html.erb
file so it is a "partial" and in the code it has written:
<%=render 'layouts/footer' %>
so my understanding is that when it sees this, goes and insert the HTML for footer file in here. Ok...
Now a few pages later it is saying:
<%= render partial: 'activitiy_items/recent' %>
so WHY this time we have the word "partial" in here but we didn't have it in the previous one?
And there somewhere else I see <%= yield :sidebar %>
So this yield
also insert HTML in its place? Well wasn't it what render
was doing?
I was hoping if another programmer instead of books explains this to me maybe I get it this time:)
render
& render partial:
render 'some_view'
is a shorthand for render partial: 'some_view'
.
render file: 'view'
will look for a file view.html.erb
and NOT _view.html.erb
(.erb
or any other renderer you use)
render
will not accept additional local variables for the partial, you need to use render partial:
as following for that:
render partial: 'some/path/to/my/partial', locals: { custom_var: 'Hello' }
(http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables)
yield
& content_for
yield
is typically used in layouts. It tells Rails to put the content for this block at that place in the layout.
- When you do
yield :something
associated with content_for :something
, you can pass a block of code (view) to display where the yield :something
is placed (see example below).
A small example about yield:
In your layout:
<html>
<head>
<%= yield :javascript_head %>
</head>
<body>
<div id="sidebar">
<%= yield :sidebar %>
</div>
</body>
In one of your view:
<% content_for :sidebar do %>
This content will show up in the sidebar section
<% end %>
<% content_for :javascript_head do %>
<script type="text/javascript">
console.log("Hello World!");
</script>
<% end %>
This will produce the following HTML:
<html>
<head>
<script type="text/javascript">
console.log("Hello World!");
</script>
</head>
<body>
<div id="sidebar">
This content will show up in the sidebar section
</div>
</body>
Posts that might help:
- Embedded Ruby -- Render vs. Yield?
- Render @object and locals vs render :partial
- Rails newbie: about yield
Links to documentation & guides:
- http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
- http://apidock.com/rails/ActionView/Helpers/CaptureHelper/content_for
- http://apidock.com/rails/ActionController/Base/render
About render , render :partial and yield
render :template and render :partial are two files in rails..
render :template are mostly created according to an action with syntax demo.html.erb
render :partial are reuseable and called from different views , are shared among many pages in application and syntax is _demo.html.erb
yield and render..
Yield is a way to call a block of code with its output but render will include a partial page template where it is called. In rails yield is mostly used in layout whereas render is used in actions or their templates
Some developers think of redirect_to as a sort of goto command, moving execution from one place to another in your Rails code. This is not correct. Your code stops running and waits for a new request for the browser. It just happens that you've told the browser what request it should make next, by sending back an HTTP 302 status code.
Consider these actions to see the difference:
def index
@books = Book.all
end
def show
@book = Book.find_by(id: params[:id])
if @book.nil?
render action: "index"
end
end
With the code in this form, there will likely be a problem if the @book
variable is nil. Remember, a render :action
doesn't run any code in the target action, so nothing will set up the @books variable that the index view will probably require. One way to fix this is to redirect instead of rendering:
def index
@books = Book.all
end
def show
@book = Book.find_by(id: params[:id])
if @book.nil?
redirect_to action: :index
end
end
With this code, the browser will make a fresh request for the index page, the code in the index method will run, and all will be well.
The only downside to this code is that it requires a round trip to the browser: the browser requested the show action with /books/1 and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to /books/, the browser complies and sends a new request back to the controller asking now for the index action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen.
While in a small application, this added latency might not be a problem, it is something to think about if response time is a concern. We can demonstrate one way to handle this with a contrived example:
def index
@books = Book.all
end
def show
@book = Book.find_by(id: params[:id])
if @book.nil?
@books = Book.all
flash.now[:alert] = "Your book was not found"
render "index"
end
end
This would detect that there are no books with the specified ID, populate the @books instance variable with all the books in the model, and then directly render the index.html.erb template, returning it to the browser with a flash alert message to tell the user what happened.