Search code examples
ruby-on-railssoftware-quality

Is there a good way to validate each model attribute separately?


I'm working on an application that requires me to fill a model through several pages.

Hence, I need to validate each portion of attributes presented in each form.

I've found a way to do so, but I'm wondering if this seems correct, and if I could improve my code ?

def general
  @user = User.new
end

def save_general
  session[:user] ||= {}
  @user = User.new(params[:user].permit(:first_name))
  
  #Apparently, I need to run this once, to populate the errors array.
  @user.valid?

  unless @user.errors[:first_name].empty?
    render :general, status: :unprocessable_entity
  else
    session[:user][:first_name] = params[:user][:first_name]
  end
end

Solution

  • You can easily move parts of the buisness logic out of the model into separate classes:

    class UserNameForm
      include ActiveModel::Model
      include ActiveModel::Attributes
      attribute :first_name, :string
      validates :first_name, presence: true
    
      # This will make it behave like a User in forms.
      def model_name
        User.model_name
      end
    end
    

    This is commonly referred to as the form object pattern.

    def save_general
      @form = UserNameForm.new(params[:user].permit(:first_name))
      # NEVER unless and else together
      if @form.valid?
        session[:user] ||= {}
        session[:user].merge(form.attributes)
      else
        render :general, status: :unprocessable_entity
      end
    end
    

    It's kind of questionable if you want to tuck the attributes away into the session like this. On a successful form submission you could just render the next step of the form and include the stuff that's already been filled in as hidden inputs.