Jonathan Bennett

Evolving your views: A conventional setup

A normal Rails page will pull data in the controller and present it in the view:

# app/controllers/dashboards_controller.rb
class DashboardsController < ApplicationController
	def show
		@recent_posts = Post
			.where(publish_at: [..Time.current])
			.order(publish_at: :desc)
			.limit(10)
		@recent_comments = Comment.all
			.order(create_at: :desc).limit(10)
	end
end


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

I generally try to avoid using where outside of model classes. Typically there is a concept trying to come out. Identifying it and naming it, usually with a scope is a better choice:

class Post < ApplicationRecord
	scope :published, ->(at = Time.current) { where(publish_at: [..at]) }
	scope :reverse_chronologically, -> { order(publish_at: :desc) }
end

class Comment < ApplicationRecord
	scope :reverse_chronologically, -> { order(created_at: :desc) }
end

class DashboardsController < ApplicationController
	def show
		@recent_posts = Post.published.reverse_chronologically.limit(10)
		@recent_comments = Comment.all.reverse_chronologically.limit(10)
	end
end

The other change we will want to make is to extract partials for the Post and Comment models.

<!-- app/view/posts/_post_row.html.erb -->
<li><%= link_to post.title, post %></li>
 
<!-- app/view/comments/_comment_row.html.erb -->
<li><%= link_to comment.body, post_path(comment.post_id, anchor: dom_id(comment)) %></li>

<!-- app/views/dashboards/show.html.erb -->
<div>
	<h2>Recent Posts</h2>
	
	<ul>
		<%= render partial: "posts/post_row", collection: @recent_posts %>
	</ul>
</div>

<div>
	<h2>Recent Comments</h2>
	
	<ul>
		<%= render partial: "comments/comment_row", collection: @recent_comments %>
	</ul>
</div>

Note that these aren’t the primary views of the models so we are not using the normal shorthand method of rendering them (<%= render @posts %>).

With this in place we have a very conventional starting place to improve on the basic Rails setup.