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
25endRequire 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 exceptionpermit
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)
15endReusing 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
9endMultiple 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
22endHandling Unpermitted Parameters
In Development
ruby
1# config/environments/development.rb
2config.action_controller.action_on_unpermitted_parameters = :raise
3# Raises ActionController::UnpermittedParametersLogging
ruby
1# config/environments/production.rb
2config.action_controller.action_on_unpermitted_parameters = :log
3# Logs unpermitted parametersFetch 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)
8endCommon 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
22endAPI 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
14endWith 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
19endStrong parameters are your first line of defense against malicious input!
