Jonathan Bennett

Evolving your views: Extracting a page object

Extracting our dashboard’s configuration out of the controller will let us keep our controller simple and focuses, and let us test things more easily in the future when things become more complicated. Where we want to end up is creating an object in our controller and rendering it in our view:

# app/controllers/dashboards_controller.rb
class DashboardsController < ApplicationController
	def show
		@dashboard = Dashboard.new
	end
end


<%= render @dashboard %>

We’ll start by pulling the posts and comments into the new class:

# app/models/dashboard.rb
class Dashboard
	def posts
		Post
			.where(publish_at: [..Time.current])
			.order(publish_at: :desc)
			.limit(10)
	end
	
	def comments
		Comment.all
			.order(create_at: :desc).limit(10)
	end
end

To support loading a partial to render itself, the Dashboard class also needs to implement to_partial_path

class Dashboard
	def to_partial_path
		"dashboards/dashboard"
	end
end

and our updated partial:

<!-- app/views/dashboards/_dashboard.html.erb -->
<div class="grid grid-cols-2">
	<div>
		<h2>Recent Posts</h2>
		
		<ul>
			<%= dashboard.posts.each do |post| %>
				<li><%= link_to post.title, post %></li>
			<% end %>
		</ul>
	</div>
	
	<div>
		<h2>Recent Comments</h2>
		
		<ul>
			<%= dashboard.comments.each do |comment| %>
				<li><%= link_to comment.body, 
					post_path(comment.post_id, anchor: dom_id(comment))
				%></li>
			<% end %>
		</ul>
	</div>
</div>

For this simple example there isn’t a huge win for this extraction, but as you grow your system you can treat these as reusable components. That is where isolating the component gives a benefit, and lets you build a more robust and understandable system.