'Ruby On Rails 7.0 invalid? set true in console but not in view

I´m trying to avoid to update an empty name for @post. I´m beginner in RoR and I don´t understand why in terminal I got @post.invalid? => true but in my view edit.html.erb @post.invalid? => false

posts_controller.rb

class PostsController < ApplicationController

  before_action :set_post, :only => [:edit, :show, :update, :destroy]

  def index
    @posts = Post.all
    respond_to do |format|
      format.html
      format.json { render json: @posts }
    end
  end

  def show
    respond_to do |format|
      format.html
      format.json { render json: @post }
    end
  end

  def edit
  end

  def update
    if @post.update(post_params)
      redirect_to posts_path, success: "Post updated"
    else
      puts @post.invalid? # write true
      render 'edit'
    end
  end

  def new
    @post = Post.new
  end

  def create
    post = Post.create(post_params) 
    redirect_to post_path(post.id), success: "Post created"
  end

  def destroy
    @post.destroy

    redirect_to posts_path, success: "Post deleted"
  end

  private

  def post_params
    params.require(:post).permit(:name, :content)
  end

  def set_post
    @post = Post.find(params[:id])
  end

end

post.rb

class Post < ApplicationRecord

  validates :name, presence: true

  def as_json(options = nil)
    super(only: [:name, :id, :created_at] )
  end
end

edit.html.erb

<h1>Editer l´article</h1>

<%= @post.invalid? %> <!-- write false -->

<% if @post.invalid? %> <!-- return false -->
  <div class="alert alert-danger">
    <% @post.errors.full_messages.each do |message| %>
      <%= message %>
    <% end %>
  </div>
<% end %>

<%= form_for @post do |f| %>
  <div class="form-group">
    <label>Titre de l´article</label>
    <%= f.text_field :name, class: 'form-control' %>
  </div>
  <div class="form-group">
    <label>Contenu de l´article</label>
    <%= f.text_area :content, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.submit "Modifier l´article", class: 'btn btn-primary' %>
  </div>
<% end %>

I´m confused, someone has got an idea ?



Solution 1:[1]

The methods valid? and invalid? all keep running the validation methods every time they are called, and therefore potentially change the state of the model.

If you want to just check for validity when validation has already been run, you should instead use @post.errors.present? or @post.errors.blank? which will never change the status, only read existing errors (that were added in your case when the call to update failed.

Additionally (even if it´s not the case here) calling valid? and invalid? without a context will clear out errors that had been added with validations like validate ..., on: :update.

Solution 2:[2]

The solution I found was a combination of @rewritten´s answer and this one.

So...

<h1>Editer l´article</h1>

<% if @post.errors.present? %>
  <div class="alert alert-danger">
    <% @post.errors.full_messages.each do |message| %>
      <%= message %>
    <% end %>
  </div>
<% end %>

<%= form_for @post, data: { turbo: false} do |f| %>
  <div class="form-group">
    <label>Titre de l´article</label>
    <%= f.text_field :name, class: 'form-control' %>
  </div>
  <div class="form-group">
    <label>Contenu de l´article</label>
    <%= f.text_area :content, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.submit "Modifier l´article", class: 'btn btn-primary' %>
  </div>
<% end %>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 rewritten
Solution 2 J.BizMai