David Geismar
David Geismar

Reputation: 3422

Prepopulating form with data after API sends error in JSON

I have a frontend rails app that is requesting a rails API. When my user wants to create an account, he is submitting the account form on the front-end app :

<h1>Create Account</h1>
<form action="http://localhost:3000/accounts" method="post">
  <input name="authenticity_token" value="<%= form_authenticity_token %>" type="hidden">
  <div class="form-group">
    <%= label_tag 'account[name]', "name" %>
    <input type="text" name="account[name]" required>
  </div>
  <div class="form-group">
    <%= label_tag "account[contact_mail]", "E-Mail" %>
    <input type="text" name= "account[contact_mail]" required>
  </div>
  <div class="form-group">
    <%= label_tag "account[contact_tel]", "Telephone" %>
    <input type="text" name= "account[contact_tel]" required>
  </div>
  <div class="form-group">
    <%= label_tag "account[iban]", "Iban" %>
    <input type="text" name= "account[iban]">
  </div>
  <div class="form-group">
    <%= label_tag "account[bic]", "Bic" %>
    <input type="text" name= "account[bic]">
  </div>
  <input type="submit">
    <% if @errors %>
    <ul class="list-unstyled">
      <%@errors.each do |error|%>
        <li class="has-error"><%=error%></li>
      <% end -%>
    </ul>
  <% end -%>
</form>

On submit the method create from the front-end app account controller is called. The create method from the front-end app is then calling the create method on the rails API which is responsible for updating the database and rendering JSON to the front end app.

1) AccountController#create from the front-end app :

def create

  # Post sur API create Account
 @response =   HTTParty.post(ENV['API_ADDRESS']+'api/v1/accounts',
  :body => { :name => params[:account][:name],
             :contact_mail => params[:account][:contact_mail],
             :contact_tel =>  params[:account][:contact_tel],
             :legal_status => params[:account][:legal_status],
             :iban => params[:account][:iban],
             :bic => params[:account][:bic]
           }.to_json,
  :headers => { 'X-User-Email' => session[:user_email], 'X-User-Token'=> session[:user_token], 'Content-Type' => 'application/json' } )
  # Erreur Mauvais Auth Token
  if @response["error"] == "You need to sign in or sign up before continuing."
    redirect_to unauthorized_path
  # erreur de validation
  elsif @response["errors"]
    @errors = @response["errors"]
    flash[:alert] = "heello"
    render :new
  else
    account_id = @response["account"]["id"]
    redirect_to account_path(account_id)
  end
end

2) AccountController#create from the API :

def create @account = Account.new(account_params.merge(admin: current_user)) authorize @account if @account.save render :show else render_error end end

render error is a method that render errors in JSON format :

  def render_error
    render json: { errors: @account.errors.full_messages }, status: :unprocessable_entity
  end

If there are validations errors when submitting the from to the API, I display them on the front end app next to the form :

 <% if @errors %>
        <ul class="list-unstyled">
          <%@errors.each do |error|%>
            <li class="has-error"><%=error%></li>
          <% end -%>
        </ul>

My problem is that I also wish to prepopulate the form with the data the user already submitted for better user experience.

I know there are already posts about how to prepopulate forms with rails in case of validation errors but I feel they did not really address my problem with this "double app pattern" and with my front-end app not having any models (all models / DB interactions are dealt in the API)

How can I prepopulate my form with the user's input after I receive an error from my JSON API ?

Upvotes: 0

Views: 198

Answers (1)

mmartinson
mmartinson

Reputation: 240

In the form you have, you could add value attributes to the input fields that populate with irb instance variables <input type="text" name="account[name]" value="<%= @account_name %>" required>

Then in AccountController#create, set the instance variables based on the the params you received when you want to display the invalid data.

```

elsif @response["errors"]
  @errors = @response["errors"]

  #new code
  @account_name = params[:account][:name]
  #set each variable, extra to method or class for cleaner style

  flash[:alert] = "heello"
  render :new

```

When the form initially renders these variables will be uninitialize/nil so there will be no values in the form boxes, and then you can explicitly set them in the controller when the validation fails but you want to maintain data in the form.

This is definitely an overly-manual way to accomplish maintaining the form state, and I suggest if you want to reuse the pattern in your app you take a look at using form_for. This post might give you some insight into doing that with plain ruby objects instead of model objects. Is it possible to create form for simple class

Upvotes: 1

Related Questions