Difference between Render and Render Partial and Y

2019-01-13 03:06发布

问题:

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:)

回答1:

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


回答2:

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



回答3:

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.