Coder_Nick
Coder_Nick

Reputation: 851

Trying to display error messages within a partial form

My app has a portfolio that has many positions. Each position has many movements.

Within a portfolio I am showing all of my positions.

<p>
  <strong>Name:</strong>
  <%= @portfolio.name %>
</p>

<%= render partial: @positions %>

<%= render 'positions/form' %>

<%= link_to 'Edit', edit_portfolio_path(@portfolio) %> |
<%= link_to 'Back', portfolios_path %>

My position partial is written like this:

<ul>
  <li><%= position.name %></li>
  <li><%= position.quantity %></li>
  <li><%= position.ticker %></li>
</ul>
<%= form_for [@portfolio, position, @movement] do |f| %>
  <div id = "movement-errors">
    <% if @movement.errors.any? %>
      <%= render partial: 'movements/movement_error_messages' %>
    <% end %>
  </div>
  <div class="field">
    <%= f.label :quantity %>
    <%= f.text_field :quantity %>
 </div>
 <div class="actions">
   <%= f.submit %>
 </div>
<% end %>

With my error partial like this:

<% if @movement.errors.any? %>
  <div id = "error_explanation">
    <div class = "alert alert-danger">
      The form contains <%= pluralize(@movement.errors.count, "error") %>.
    </div>
    <ul>
      <% @movement.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

When I submit an empty quantity I want the error message to render on the same page. As it stands right now, when I submit an empty form, I'm redirected to the Movements#new page where I have a form and it has an update button.

My Movement controller is built like:

class MovementsController < ApplicationController
  before_action :load_portfolio_and_position

  def create
    @movement = Movement.new(movement_params)
    @movement.position_id = @position.id
    @movement.update_price
    @movement.date = DateTime.now
    @movement.trade ='buy'

    respond_to do |format|
      if @movement.save
        @position.update_attribute(:quantity, (@movement.quantity + @position.quantity))
        format.html { redirect_to @portfolio, notice: 'Movement was successfully created.' }
        format.js
      else
        format.html { render :new }
        format.json { render json: @movement.errors, status: :unprocessable_entity }
        format.js
      end
    end
  end

I just want to submit either valid or invalid data and have it be handled in the same page.

Upvotes: 0

Views: 1056

Answers (1)

max
max

Reputation: 102443

Use local variables instead when building partials. This makes them truly reusable and useful:

# app/views/shared/_errors.html.erb
<% if object.errors.any? %>
  <div id = "error_explanation">
    <div class = "alert alert-danger">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
      <% object.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

This means we can render it like:

<%= render 'shared/errors', object: @movement %>

I just want to submit either valid or invalid data and have it be handled in the same page.

Thats not how Rails works and for good reason. When you submit a form and the form is invalid you render a view which displays the error messages and form in so that the user can correct the issues.

Redirecting back would put any user entered data in the query string where it is less secure or rely on using the session in a way that violates REST.

format.html { render :new }

Does not call the new action in your controller. It just looks for a /movements/new.html.erb view and renders it.

You can of course have it render any other view you want. Like render template: 'foo/bar'.

Upvotes: 1

Related Questions