Katharina Schreiber
Katharina Schreiber

Reputation: 1371

Multistep Validations with Wicked: Validation failed: Street can't be blank

I have a multistep form. It's a bit complicated, cause basically first the user gets created through registrations controller, then get's redirected to a form. Speaking precisely, it's not a multistep form, but more of a two-step registration. To do validations with those is quite triky, but I figured the way, which works. In my User.rb I defined validations as follows:

validates :first_name, presence: true, :on => :create
validates :last_name, presence: true, :on => :create
validates :street, presence: true, :on => :update

But now I am having issues, with showing the errors to a user on that update step. I have the update action in my UserStepsController:

class UserStepsController < ApplicationController
    include Wicked::Wizard
    steps :address
    #respond_to :html, :js

    def show
      @user = current_user || User.from_omniauth(request.env["omniauth.auth"])
      render_wizard
    end


    def update
      @user = current_user || User.from_omniauth(request.env["omniauth.auth"])
        if @user.update!(user_params)
            render_wizard @user
        else
            render :show
        end
    end


    private

    def user_params
        params.require(:user).permit(:email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :street, :house_number, :city, :zip_code)
    end

    def redirect_to_finish_wizard(options = nil, params = nil)
        redirect_to new_user_profile_path(current_user)
    end

end

So, if the User can't be updated, cause the validations have failed, I would love to show error messages about what went wrong. For this in my address.html.erb I defined this behaviour:

<%= form_for @user, url: wizard_path do |f| %>
    <% if @user.errors.any? %>
        <div class="error_explanation">
            <h2><%= pluralize(@user.errors.count, "error") %> prevented this record from being saved:</h2>
                <ul>
                    <% @user.errors.full_messages.each do |message| %>
                        <li><%= message %></li>
                    <% end %>
                </ul>
        </div>
    <% end %>

        <div class="row second 1">
            <div class="column">
              <div class="field wizard">
                <%= f.label :street %><br />
                <%= f.text_field :street, class: 'form-control' %>
              </div>
            </div>

This won't show the errors, but throws active record error instead:

ActiveRecord::RecordInvalid in UserStepsController#update
Validation failed: Street can't be blank

Extracted source (around line #14):

12 def update
13 @user = current_user || User.from_omniauth(request.env["omniauth.auth"])
14 if @user.update!(user_params)
15 render_wizard @user
16 else
17 render :show

What am I doing wrong?

Upvotes: 0

Views: 184

Answers (2)

Katharina Schreiber
Katharina Schreiber

Reputation: 1371

The problem was the update action. I changed it as follows.

def update
      @user = current_user || User.from_omniauth(request.env["omniauth.auth"])
        if @user.update_attributes(user_params)
            render_wizard @user
        else
            render :address
        end
    end

I also could change my view, to lead the the shared error messages:

<%= form_for @user, url: wizard_path do |f| %>
<%= render "devise/shared/error_messages" %>

This works for both creating and updating a @user:

<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-error">
      <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |message| %>
      <li>* <%= message %></li>
    <% end %>
    </ul>
  </div>
<% end %>

Upvotes: 0

Roman Alekseiev
Roman Alekseiev

Reputation: 1920

update vs update!. If I remember update! runs save! instead of save on model. It means that it runs exception if record is not valid. update will try to call save method which runs validations

Upvotes: 1

Related Questions