-
Notifications
You must be signed in to change notification settings - Fork 0
19 Categories Show
Now that we have relationships between posts and categories, seems like we ought to be able to browse posts by categories. Let's make categories#show
do just that.
What will we need to do in the controller's show
method? As usual for a show
action, we'll grab the appropriate instance of Category
.
app/controllers/categories_controller.rb
def show
@category = Category.find params[:id]
end
In our view, we'll want to iterate over each post in that category. If we call @category.posts, it will load the posts from the database at that time. Since we know we'll always need the posts in this view, we can load them in the controller in the very same query as the category itself using includes
.
def show
@category = Category.includes(:posts).find(params[:id])
end
Moving on to the view, let's start simple. We'll display the title and description of our category.
New file: app/views/categories/show.html.erb
<div class="category">
<h2><%= @category.title %></h2>
<div class="description"><%= @category.description %></div>
</div>
Remember the sidebar
attribute we added? How can we display the value of that attribute in the sidebar? The thing is, the sidebar is in the layout, not in the view. Just as we yield
the output of our view in the layout, we can yield
other data to the layout, using the content_for
method from ActionView::Helpers::CaptureHelper
.
Calling #content_for stores a block of markup in an identifier for later use. In order to access this stored content in other templates, helper modules or the layout, you would pass the identifier as an argument to
content_for
.
Note:
yield
can still be used to retrieve the stored content, but callingyield
doesn't work in helper modules, whilecontent_for
does.
Let's define a helper method to store data in a :sidebar
identifer.
app/helpers/application_helper.rb
def sidebar(sidebar_content)
content_for(:sidebar) { sidebar_content }
end
We can then call that method from our view to store some data. We'll add it at the very beginning of the view.
app/views/categories/show.html.erb
<% sidebar(@category.sidebar) -%>
Now the :sidebar
identifier will be storing the value of @category.sidebar
. We can use yield
in our layout to retrieve that data and display it under the links in our sidebar.
app/layouts/application.html.erb
<nav id="sidebar">
<%= link_to 'Submit a new link', new_post_path %>
<%= link_to 'Submit a new text post', new_post_path(post_type: :text) %>
<%= link_to 'Create a new category', new_category_path %>
<div><%= yield :sidebar %></div>
</nav>
Let's add a tiny bit of CSS:
app/assets/stylesheets/style.scss
.category {
h2 {
margin-top: 0;
}
.description {
padding-bottom: 0.5em;
border-bottom: 1px solid gray;
margin-bottom: 0.5em;
}
}
If you can see the title, description, and sidebar for categories, go ahead an make an incremental commit. I'm going to use the abbreviation "WIP" to indicate that this commit contains a work-in-progress.
$ git add .
$ git commit -m "WIP display category data on `categories/show`."
There's something very obviously missing from this page still: Posts. We really want them to display just as they do on posts/index. Are you thinking what I'm thinking? It's partial time.
Extract post display from posts/index into a partial, and render the partial in categories/show to display only the posts in a particular category.