class UsersController < ApplicationController
before_action :validate_user_id, only: [:show]
before_action :validate_search_params, only: [:search]
before_action :validate_sort_params, only: [:index]
# SECURE: Parameterized query
def show
user_id = params[:id].to_i
@user = User.where('id = ?', user_id).first
if @user
render json: @user.as_json(except: [:password_digest, :reset_token])
else
render json: { error: 'User not found' }, status: 404
end
end
# SECURE: Hash conditions and parameterized queries
def search
name = params[:name]&.strip
department = params[:department]&.strip
status = params[:status]&.strip
# Start with all users
users = User.all
# Apply filters safely using hash conditions
if name.present?
users = users.where('name ILIKE ?', "%#{name}%")
end
if department.present?
users = users.where(department: department)
end
if status.present?
users = users.where(status: status)
end
# Limit results for performance
@users = users.limit(100)
render json: @users
end
# SECURE: Validated parameters with safe ActiveRecord methods
def filter_by_salary
min_salary = params[:min_salary]&.to_f || 0
max_salary = params[:max_salary]&.to_f
# Validate salary ranges
if min_salary < 0
return render json: { error: 'Invalid minimum salary' }, status: 400
end
users = User.where('salary >= ?', min_salary)
if max_salary.present? && max_salary > min_salary
users = users.where('salary <= ?', max_salary)
end
@users = users.limit(100)
render json: @users
end
# SECURE: Whitelisted sort columns
def index
sort_column = params[:sort] || 'name'
sort_direction = params[:direction]&.upcase || 'ASC'
# Input validation already done in before_action
@users = User.order("#{sort_column} #{sort_direction}").limit(100)
render json: @users
end
private
def validate_user_id
unless params[:id]&.match?(/\A\d+\z/)
render json: { error: 'Invalid user ID format' }, status: 400
end
end
def validate_search_params
# Validate name length
if params[:name].present? && params[:name].length > 100
render json: { error: 'Name search term too long' }, status: 400
return
end
# Validate department
if params[:department].present?
valid_departments = %w[IT HR Finance Marketing Sales]
unless valid_departments.include?(params[:department])
render json: { error: 'Invalid department' }, status: 400
return
end
end
# Validate status
if params[:status].present?
valid_statuses = %w[active inactive suspended pending]
unless valid_statuses.include?(params[:status])
render json: { error: 'Invalid status' }, status: 400
return
end
end
end
def validate_sort_params
# Whitelist allowed sort columns
allowed_columns = %w[name email department created_at updated_at salary]
sort_column = params[:sort] || 'name'
unless allowed_columns.include?(sort_column)
render json: { error: 'Invalid sort column' }, status: 400
return
end
# Validate sort direction
sort_direction = params[:direction]&.upcase || 'ASC'
unless %w[ASC DESC].include?(sort_direction)
render json: { error: 'Invalid sort direction' }, status: 400
return
end
# Store validated params
params[:sort] = sort_column
params[:direction] = sort_direction
end
end