You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ember与Rails中的验证错误处理方案咨询

Hey there! Great to hear you're finding Ember productive even as a new user—let's fix that error handling issue for you.

First, let's break down what's off with your current approach, then walk through the Ember-friendly way to handle both backend and frontend validation errors.

What's Wrong With Your Current Setup

Right now you're manually maintaining an errors array in your controller, but Ember Data is designed to automatically handle JSON API-compliant errors from your Rails backend. When a save() fails, Ember Data parses those errors and attaches them directly to the model instance's errors property (a DS.Errors object), so you don't need to copy them over manually.

Step 1: Clean Up Your Controller

Let's remove the manual errors tracking and let Ember Data do the heavy lifting. We'll also use arrow functions to avoid self = this boilerplate:

// controllers/categories/new.js
import Controller from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class CategoriesNewController extends Controller {
  @service store;
  @tracked title = "";
  @tracked description = "";
  @tracked category; // Track the category instance so the template can access its errors

  @action submitData(e) {
    e.preventDefault();
    
    // Create and track the category record
    this.category = this.store.createRecord("category", {
      title: this.title,
      description: this.description,
    });

    this.category.save()
      .then(() => this.transitionToRoute("categories"))
      .catch(() => {
        // No need to manually assign errors—Ember Data already did this!
        // You can add optional logic here like scrolling to the first error
      });
  }
}

Step 2: Update Your Template to Use Model Errors

Now you can directly reference the model's errors in your template. You can show errors per-field or display all errors together:

{{! templates/categories/new.hbs }}
<form {{on "submit" this.submitData}}>
  {{! Title field with errors }}
  <div class="mb-4">
    <label class="block mb-1" for="title">Title</label>
    <input 
      type="text" 
      id="title"
      value={{this.title}} 
      {{on "input" (fn (mut this.title))}}
      class="border rounded p-2 w-full"
    />
    {{#each this.category?.errors.title as |error|}}
      <p class="mt-1 text-sm font-medium text-red-700">{{error.message}}</p>
    {{/each}}
  </div>

  {{! Description field with errors }}
  <div class="mb-4">
    <label class="block mb-1" for="description">Description</label>
    <input 
      type="text" 
      id="description"
      value={{this.description}} 
      {{on "input" (fn (mut this.description))}}
      class="border rounded p-2 w-full"
    />
    {{#each this.category?.errors.description as |error|}}
      <p class="mt-1 text-sm font-medium text-red-700">{{error.message}}</p>
    {{/each}}
  </div>

  {{! Optional: Show all global/field errors }}
  {{#each this.category?.errors.messages as |message|}}
    <p class="mb-2 text-sm font-medium text-red-700">{{message}}</p>
  {{/each}}

  <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">Save Category</button>
</form>

Step 3: Adding Client-Side Validation in the Model

If you want to add frontend validation (before sending to Rails), you can define a validation method directly in your model. This keeps your validation logic organized in the model layer where it belongs:

// models/category.js
import Model, { attr } from '@ember-data/model';

export default class CategoryModel extends Model {
  @attr('string') title;
  @attr('string') description;

  // Custom client-side validation
  validate() {
    const errors = [];

    if (!this.title?.trim()) {
      errors.push({ attribute: 'title', message: 'Title can\'t be blank' });
    }

    if (this.description?.length < 5) {
      errors.push({ attribute: 'description', message: 'Description must be at least 5 characters' });
    }

    return errors;
  }
}

Then update your controller to run this validation before saving:

@action submitData(e) {
  e.preventDefault();
  
  this.category = this.store.createRecord("category", {
    title: this.title,
    description: this.description,
  });

  // Run client-side validation first
  const validationErrors = this.category.validate();
  if (validationErrors.length) {
    // Add validation errors to the model's errors object
    validationErrors.forEach(error => {
      this.category.errors.add(error.attribute, error.message);
    });
    return; // Don't send to backend if validation fails
  }

  this.category.save()
    .then(() => this.transitionToRoute("categories"))
    .catch(() => {});
}

Key Notes

  • Ember Data automatically parses your Rails API's JSON API errors because your response follows the spec—this is why the errors show up on the model's errors property without extra work.
  • The DS.Errors object has handy methods like get('attribute') to get errors for a specific field, and messages to get all error strings at once.
  • Keeping validation logic in the model follows Ember's convention of separating concerns, making your code more maintainable.

内容的提问来源于stack exchange,提问作者Abeid Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:02:47