Skip
Arish's avatar

42. Strong Parameters


Strong Parameters

Strong Parameters is a security feature in Rails that prevents mass assignment vulnerabilities. It ensures only explicitly permitted parameters are used for model creation or updates.

Why Strong Parameters?

Without protection, malicious users could inject unwanted attributes:

ruby
1# Dangerous - user could set admin: true
2User.create(params[:user])
3
4# With strong parameters - only permitted fields
5User.create(user_params)

Basic Usage

In Controllers

ruby
1class ArticlesController < ApplicationController
2  def create
3    @article = Article.new(article_params)
4    if @article.save
5      redirect_to @article
6    else
7      render :new
8    end
9  end
10  
11  def update
12    @article = Article.find(params[:id])
13    if @article.update(article_params)
14      redirect_to @article
15    else
16      render :edit
17    end
18  end
19  
20  private
21  
22  def article_params
23    params.require(:article).permit(:title, :body, :published)
24  end
25end

Require vs Permit

require

Ensures the parameter hash exists:

ruby
1# params = { article: { title: "Hello" } }
2params.require(:article)
3# => { title: "Hello" }
4
5# params = {}
6params.require(:article)
7# => ActionController::ParameterMissing exception

permit

Specifies which keys are allowed:

ruby
1params.require(:article).permit(:title, :body)
2# Only allows :title and :body
3
4# Unpermitted keys are ignored
5# params = { article: { title: "Hi", admin: true } }
6# => { title: "Hi" } (admin is removed)

Permitting Different Types

Scalar Values

ruby
1# Simple attributes
2params.require(:user).permit(:name, :email, :age)
3
4# Specific types
5params.require(:user).permit(
6  :name,           # string
7  :age,            # integer
8  :active,         # boolean
9  :rating          # decimal
10)

Arrays

ruby
1# Array of scalar values
2params.require(:article).permit(:title, tag_ids: [])
3
4# Example params:
5# { article: { title: "Hi", tag_ids: [1, 2, 3] } }
6
7# Array of permitted values
8params.require(:user).permit(:name, roles: [])

Nested Hashes

ruby
1# Single nested hash
2params.require(:user).permit(:name, address: [:street, :city, :zip])
3
4# Example params:
5# { user: { name: "John", address: { street: "123 Main", city: "NYC" } } }
6
7# Hash with any keys (use sparingly)
8params.require(:user).permit(:name, metadata: {})

Nested Attributes

ruby
1# For accepts_nested_attributes_for
2params.require(:article).permit(
3  :title,
4  :body,
5  comments_attributes: [:id, :body, :_destroy]
6)
7
8# Example params:
9# { article: { 
10#     title: "Hello",
11#     comments_attributes: [
12#       { id: 1, body: "Great!" },
13#       { body: "New comment" }
14#     ]
15#   }
16# }

Advanced Patterns

Conditional Permits

ruby
1def user_params
2  permitted = [:name, :email]
3  permitted << :role if current_user.admin?
4  permitted << :password if action_name == 'create'
5  
6  params.require(:user).permit(permitted)
7end
8
9# Or with merge
10def user_params
11  base_params = [:name, :email]
12  admin_params = current_user.admin? ? [:role, :verified] : []
13  
14  params.require(:user).permit(base_params + admin_params)
15end

Reusing Permit Lists

ruby
1class ArticlesController < ApplicationController
2  PERMITTED_PARAMS = [:title, :body, :category_id, tag_ids: []]
3  
4  private
5  
6  def article_params
7    params.require(:article).permit(PERMITTED_PARAMS)
8  end
9end

Multiple Models

ruby
1class RegistrationsController < ApplicationController
2  def create
3    @user = User.new(user_params)
4    @user.build_profile(profile_params)
5    
6    if @user.save
7      redirect_to dashboard_path
8    else
9      render :new
10    end
11  end
12  
13  private
14  
15  def user_params
16    params.require(:user).permit(:email, :password, :password_confirmation)
17  end
18  
19  def profile_params
20    params.require(:profile).permit(:name, :bio, :avatar)
21  end
22end

Handling Unpermitted Parameters

In Development

ruby
1# config/environments/development.rb
2config.action_controller.action_on_unpermitted_parameters = :raise
3# Raises ActionController::UnpermittedParameters

Logging

ruby
1# config/environments/production.rb
2config.action_controller.action_on_unpermitted_parameters = :log
3# Logs unpermitted parameters

Fetch with Default

ruby
1# Get parameter with default
2page = params.fetch(:page, 1)
3per_page = params.fetch(:per_page, 25)
4
5# With permit
6def search_params
7  params.fetch(:search, {}).permit(:query, :category, :sort)
8end

Common Patterns

Create vs Update

ruby
1class UsersController < ApplicationController
2  def create
3    @user = User.new(create_params)
4  end
5  
6  def update
7    @user.update(update_params)
8  end
9  
10  private
11  
12  def create_params
13    params.require(:user).permit(:name, :email, :password, :password_confirmation)
14  end
15  
16  def update_params
17    # Don't require password on update
18    permitted = [:name, :email]
19    permitted += [:password, :password_confirmation] if params[:user][:password].present?
20    params.require(:user).permit(permitted)
21  end
22end

API Controllers

ruby
1class Api::ArticlesController < Api::BaseController
2  def create
3    @article = current_user.articles.create!(article_params)
4    render json: @article, status: :created
5  end
6  
7  private
8  
9  def article_params
10    params.require(:data)
11          .require(:attributes)
12          .permit(:title, :body, :published)
13  end
14end

With Concerns

ruby
1# app/controllers/concerns/article_params.rb
2module ArticleParams
3  extend ActiveSupport::Concern
4  
5  private
6  
7  def article_params
8    params.require(:article).permit(permitted_article_attributes)
9  end
10  
11  def permitted_article_attributes
12    [:title, :body, :category_id, tag_ids: []]
13  end
14end
15
16# app/controllers/articles_controller.rb
17class ArticlesController < ApplicationController
18  include ArticleParams
19end

Strong parameters are your first line of defense against malicious input!