Skip to content

Instantly share code, notes, and snippets.

@walterdavis
Last active June 23, 2017 22:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save walterdavis/3a960dfdc529a5adf0dd6cff9e644fb0 to your computer and use it in GitHub Desktop.
Save walterdavis/3a960dfdc529a5adf0dd6cff9e644fb0 to your computer and use it in GitHub Desktop.

Refactoring a view with partials

Rails gives you a lot of functionality for free if you know how to name things and where to place them in the file tree.

For example, look at the following stages of refactoring a list of child elements to the parent element, in the #show page.

Stage 1

class Article < ActiveRecord::Base
  has_many :comments
  has_many :people, through: :comments
end
class Comment < ActiveRecord::Base
  belongs_to :article
  belongs_to :person
  delegates :commenter, to: :person 
end
class Person < ActiveRecord::Base
  has_many :comments
  alias_attribute :commenter, :full_name
  def full_name
    [first_name, last_name].join(' ')
  end
end
class ArticlesController < ApplicationController
  def show
    @article = Article.includes(:people, :comments).find(params[:id])
  end
  ...
end
<!-- views/articles/show.html.erb -->
...
<h2>Comments:</h2>
<%- for comment in @article.comments do ->
<h3><%= comment.commenter %></h3>
<%= simple_format comment.body %>
<%- end %>

Stage 2

Get the join out of the view

class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])
    @comments = @article.includes(:people).comments
  end
  ...
end
<!-- views/articles/show.html.erb -->
...
<h2>Comments:</h2>
<%- for comment in @comments do ->
<h3><%= comment.commenter %></h3>
<%= simple_format comment.body %>
<%- end %>

Stage 3

Make a partial for the comments

<!-- views/comments/_comment.html.erb -->
<h3 class="comment-author"><%= comment.commenter %></h3>
<%= simple_format comment.body %>

Now you can do this in your articles view

<!-- views/articles/show.html.erb -->
...
<h2>Comments:</h2>
<%= render @comments %>

Not only is this easier to read, it also means you can render a comment or comments elsewhere

class PeopleController < ApplicationController
  ...
  def show
    ...
    @recent_comments = @person.comments.order(:id).reverse.limit 5
    ...
  end
  ...
end
/* assets/stylesheets/people.css */
.recent-comments .comment-author {
  display: none;
}
<!-- views/people/show.html.erb -->
...
<aside class="recent-comments">
<h2>What I’ve said lately:</h2>
<%= render partial: 'comments/comment', collection: @recent_comments %>
</aside>

No additional work needed, besides collecting the list of comments. Rails knows how to render them because the partial is in the correct views folder and is named for the model. You can override any and all of these conventions, but if you follow the conventions, you don’t have to remember all the arguments needed to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment