Skip to content

Instantly share code, notes, and snippets.

@javierav
Last active March 20, 2026 20:24
Show Gist options
  • Select an option

  • Save javierav/ee770365928cc179ea72efda3491eb88 to your computer and use it in GitHub Desktop.

Select an option

Save javierav/ee770365928cc179ea72efda3491eb88 to your computer and use it in GitHub Desktop.
class PostsController < ApplicationController
include Confirmable
before_action :build_post, only: %i[index new create]
before_action :find_post, only: %i[show edit update destroy]
before_action :assign_attributes, only: %i[create update]
before_action :authorize_post, only: %i[new create show edit update destroy]
after_action :verify_authorized
after_action :verify_policy_scoped, only: :index
def index
authorize Post
@pagy, @posts = pagy(:offset, policy_scope(scope).filtered_by(filter_params).order(order_params))
end
def create
if @post.save
redirect_to @post
else
render :new, status: :unprocessable_entity
end
end
def update
if @post.save
redirect_to @post
else
render :edit, status: :unprocessable_entity
end
end
def destroy
with_confirmation do
if @post.destroy
redirect_to posts_path
else
redirect_to @post
end
end
end
private
def scope
Post
end
def build_post
@post = scope.build
end
def find_post
@post = policy_scope(scope).find(params[:id])
end
def assign_attributes
@post.assign_attributes(permitted_attributes(@post))
end
def authorize_post
authorize @post
end
def filter_params
params.permit()
end
end
module Confirmable
def with_confirmation
if params[:confirm] == "true"
yield
else
render status: :unprocessable_entity
end
end
end
module OrderParams
extend ActiveSupport::Concern
included do
with_options instance_writer: false do
class_attribute :order_by_param, default: :order_by
class_attribute :order_param, default: :order
class_attribute :order_asc, default: "asc"
class_attribute :order_desc, default: "desc"
class_attribute :default_order_by, default: :id
class_attribute :default_order, default: :desc
class_attribute :allowed_order_params, default: []
end
helper_method :default_order_by, :default_order, :allowed_order_params, :current_order_by, :current_order
end
def current_order
case params[order_param]&.downcase
when order_asc
"asc"
when order_desc
"desc"
else
default_order
end
end
def current_order_by
if allowed_order_params.map(&:to_s).include?(params[order_by_param])
params[order_by_param]
else
default_order_by
end
end
def order_params
{ current_order_by => current_order }
end
end
module ChangeMethods
extend ActiveSupport::Concern
included do
before_action :change_pagy_locale
around_action :change_locale
around_action :change_timezone
end
def change_pagy_locale
@pagy_locale = Current.locale || "es"
end
def change_locale(&)
I18n.with_locale(Current.locale || "es", &)
end
def change_timezone(&)
Time.use_zone(Current.timezone || "Europe/Madrid", &)
end
end
module RequestIdentification
extend ActiveSupport::Concern
included do
before_action :identify_request
end
def identify_request
Current.ip_address = request.remote_ip
Current.user_agent = request.user_agent
Current.request_id = request.request_id
end
end
module Rescues
extend ActiveSupport::Concern
included do
rescue_from Pundit::NotAuthorizedError, with: :render403
rescue_from ActiveRecord::RecordNotFound, with: :render404
rescue_from ActionController::UnknownFormat, with: :render406
end
def render403
respond_to do |format|
format.json { head 403 }
format.any { redirect_to(root_path) }
end
end
def render404
respond_to do |format|
format.json { head 404 }
format.any { redirect_to(root_path) }
end
end
def render406
head 406
end
end
module Layout
extend ActiveSupport::Concern
included do
layout :custom_layout
end
private
def custom_layout
if turbo_frame_request?
"turbo_rails/frame"
elsif %w[home pages sessions passwords].include?(controller_name) && !authenticated?
"public"
else
"application"
end
end
end
module Authentication
extend ActiveSupport::Concern
included do
before_action :require_authentication
helper_method :authenticated?
end
class_methods do
def allow_unauthenticated_access(**)
skip_before_action(:require_authentication, **)
end
end
private
def authenticated?
resume_session
end
def require_authentication
resume_session || request_authentication
end
def resume_session
Current.session ||= find_session_by_cookie
end
def find_session_by_cookie
Session.find_by(id: cookies.signed[:session_id])&.tap { |session| session.touch if session.updated_at < 1.minute.ago }
end
def request_authentication
session[:return_to_after_authenticating] = request.url
redirect_to new_session_url
end
def after_authentication_url
session.delete(:return_to_after_authenticating) || root_url
end
def start_new_session_for(account)
account.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
Current.session = session
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
end
end
def terminate_session
Current.session.destroy
cookies.delete(:session_id)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment