ruby.rails.correctness.rails-no-render-after-save.rails-no-render-after-save

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Found a call to render $T after calling $T.save. Do not call render after calling save on an ActiveRecord object. Reloading the page will cause the state-changing operation to be repeated which may cause undesirable side effects. Use redirect_to instead.

Run Locally

Run in CI

Defintion

rules:
  - id: rails-no-render-after-save
    mode: taint
    pattern-sources:
      - patterns:
          - pattern: $T
          - pattern-inside: |
              $T.save
              ...
    pattern-sinks:
      - patterns:
          - pattern-inside: |
              render $T
    message: Found a call to `render $T` after calling `$T.save`. Do not call
      `render` after calling `save` on an ActiveRecord object. Reloading the
      page will cause the state-changing operation to be repeated which may
      cause undesirable side effects. Use `redirect_to` instead.
    languages:
      - ruby
    severity: WARNING
    fix: redirect_to $T
    metadata:
      references:
        - https://guides.rubyonrails.org/getting_started.html#creating-a-new-article
      category: correctness
      technology:
        - rails
        - ruby
        - activerecord
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

rails-no-render-after-save.rb

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(title: "...", body: "...")

    if @article.save
      redirect_to @article
    else
      # ok: rails-no-render-after-save
      render :new, status: :unprocessable_entity
    end
  end

  def createok
    @article = Article.new(title: "...", body: "...")
    # ok: rails-no-render-after-save
    render @article
  end

  def createbad
    @article = Article.new(title: "...", body: "...")
    @article.save
    # ruleid: rails-no-render-after-save
    render @article
  end

  # this is nonsense but it "looks" like a bad ActiveRecord pattern
  def doSomethingElse
    foo = Type.new()
    foo.bar
    # ok: rails-no-render-after-save
    render foo
  end
end