First thing to check is whether your validations are setting the error state on your form object as is normal:
<%= form_with model: @foo do |f| %>
<%= f.text_field :bar %>
<%= f.submit %>
That's a normal .erb form for a mythical object @foo:
class Foo < ApplicationRecord
validates :bar, presence: true
If you try to submit this form in a browser without a value in the foo[bar] field, you will see that the resulting re-display of the :new view will have a div.field_with_errors wrapped around the input[type="text"]#foo_bar element. This class field_with_errors can be styled so that you see red text etc, pointing out where the problem exists. The @foo.errors[:full_messages] struct will contain a key-value dictionary of all the fields that have errors and a human-readable error message for each one. These messages are generated by the validations framework, and can be customized using the I18n translations system.
If you build a new dummy Rails application, and use the following command within it to create a "scaffold" for Foo, you can see this in action, along with some code that will also display a summary of errors at the top of the form page:
rails generate scaffold Foo bar:string
Edit the generated app/models/foo.rb to add the `validates` line as above.
Running this app with rails server and viewing it in a browser at localhost:3000/foos/new will show you a form, and if you submit it without entering anything, you should see the error messages. Look in the view as well as the controller to see how this is managed.
Many form helpers exist to allow you to use inline error messages (which appear in context) rather than all-together-at-the-top errors lists. Personally, I find these a bit more useable, particularly on a tall form. I really like https://github.com/bootstrap-ruby/bootstrap_form for this.