Table of Contents
- Basic Information
- Static Pages
- Routing
- Users
- Sessions
- Posts
- Comments and Replies
- Notifications
- Common Features
- Live Application
- Other Projects
Common Features
These are some features that I would like to go over which do not fit under any of the categories.
Toggling
When a model’s attribute is boolean, it sometimes make sense to have a toggling button to change them. Rather than going through forms, a simple button click is often much more simpler and effective. In mini-forum-rails, muting a post or comment is easy.
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
# POST /posts/1/mute
def mute
@post.mute = !@post.mute
@post.save(touch: false)
redirect_to @post, notice: "Notifications about this post was successfully #{@post.mute ? 'muted' : 'unmuted'}."
end
end
# config/routes.rb
Rails.application.routes.draw do
post 'posts/:id/mute' => 'posts#mute', :as => :post_mute
post 'comments/:id/mute' => 'comments#mute', :as => :comment_mute
end
Although this is technically not RESTful, since this is deviating away from the 7 actions (index, new, create, show, edit, update, destroy), this is the most straightforward and easiest to understand solution.
Below is a GIF showing the simplicity.
Searching
Users, posts, and posts of specific users can all be searched. A search parameter is given to the controller, and the controller will then pass that to the models. Ultimately, the result of the query is processed by the models, rather than the controllers. This is the most effective solution. The action responsible for this is the index. However, for querying a specific user’s posts, the action responsible is a custom posts
action that is essentially an index of the specific user’s posts.
# app/controllers/users_controller.rb
class UsersController < ApplicationController
# GET /users
def index
params[:search] = params[:search].squish unless params[:search].nil?
@users = User.search(params[:search])
end
# GET /users/1/posts
def posts
params[:search] = params[:search].squish unless params[:search].nil?
@user_posts = @user.search_post(params[:search])
end
end
# app/models/user.rb
class User < ApplicationRecord
# Returns users with a username or display name matching the search query, depending if '@' was included in the front or not
def self.search(search)
if search.blank?
User.all
elsif search.first == '@'
User.where("username LIKE ?", "%#{search[1..-1]}%")
else
User.where("display_name LIKE ?", "%#{search}%")
end
end
# Returns posts by this user with a title matching the search query
def search_post(search)
if search.blank?
self.posts
else
self.posts.where("title LIKE ?", "%#{search}%")
end
end
end
Notice how the search query is sanitized using squish
in the controller. Also notice how the search query can change depending on whether or not a special character was included (In this case, the @
character). The search can be matched to a user’s username or display name depending on input.
Below is a GIF showcasing the above functionalities.
Input Sanitation
Most user inputs are sanitized using a common helper method. There are things that need to be considered when sanitizing user inputs. Password fields should never be sanitized, and content fields should try to not remove new lines as that is not the default behavior and mini-forum-rails allows new lines for content fields.
# app/helpers/application_helper.rb
module ApplicationHelper
# Sanitizes parameters according to various rules
def sanitize(params)
params.each_key do |k|
if k == 'content'
# Squish each individual lines instead
content_array = params[k].split("\n")
for i in 0...content_array.length
content_array[i] = content_array[i].squish
end
# Rejoin the lines into one
params[k] = content_array.reject(&:blank?).join("\n")
elsif k == 'password' || k == 'password_confirmation' || k == 'current_password'
# Do not sanitize password fields
next
else
# Squish it
params[k] = params[k].squish
end
end
params
end
end
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
private
# Only allow a list of trusted parameters through.
def post_params
sanitize params.require(:post).permit(:title, :content, :notify_users)
end
end
Sanitation cleans inputs so that oddly placed whitespaces are removed. This is also important for the User Experience as it ensures that all content by other users look clean. Another thing to note is that the parameters are directly modified. This means that should a form be rejected, when Rails highlights the erroneous fields, the fields are already sanitized.
Below is a GIF showcasing the above functionalities.