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

Ember 3.19更新记录并保存至Rails API的正确方法

解决Ember Data更新Rails API记录时发送原始值的问题

看起来你遇到的核心问题是:Ember已经识别到模型属性的变更(changedAttributes()显示正确),但调用save()时发送的PATCH请求却携带了原始值。结合你的代码和Ember Data 3.19的特性,我整理了几个关键的排查和修复步骤:

1. 给模型属性指定正确的类型

你的Score模型中,wins、draws、losses没有指定属性类型,Ember Data默认会按字符串处理这些字段。当你把localStorage的字符串转成数字赋值时,虽然changedAttributes()能检测到变更,但序列化时可能因为类型不匹配,导致Ember Data没有正确把新值打包到请求中。

修改模型代码,明确指定数字类型:

// app/models/score.js
import Model, { attr } from '@ember-data/model';
export default class ScoreModel extends Model {
  @attr username;
  @attr('number') wins;
  @attr('number') draws;
  @attr('number') losses;
}

2. 优化记录获取与属性赋值逻辑

peekAll()是从本地store读取记录,但如果记录不是通过Ember Data的可编辑实例加载的,可能会出现更新不生效的情况。另外,批量赋值用setProperties()比单独赋值更规范,能确保变更被正确追踪:

// app/controllers/game.js
async sendScore() {
  const username = localStorage.getItem("username");
  if (!username) {
    console.error('请先输入用户名');
    return;
  }

  // 优先从本地store查找记录
  let entry = this.store.peekAll('score').find(score => score.username === username);
  
  // 本地没有则从后端查询
  if (!entry) {
    try {
      entry = await this.store.queryRecord('score', { username });
    } catch (error) {
      console.error('未找到该用户的分数记录:', error);
      // 如果需要自动新建记录,可以取消下面的注释
      // entry = this.store.createRecord('score', { username });
      return;
    }
  }

  // 安全解析localStorage中的数值(添加基数10避免八进制问题)
  const wins = parseInt(localStorage.getItem("wins"), 10);
  const losses = parseInt(localStorage.getItem("losses"), 10);
  const draws = parseInt(localStorage.getItem("draws"), 10);

  // 批量设置属性
  entry.setProperties({ wins, losses, draws });

  // 再次确认变更(方便调试)
  console.log('待更新的属性:', entry.changedAttributes());

  try {
    await entry.save();
    console.log('分数更新成功!');
  } catch (error) {
    console.error('更新失败:', error);
    // 这里可以添加用户提示,比如显示错误信息到页面
  }
}

3. 确认序列化器与Rails后端参数格式匹配

Ember Data默认使用JSON API格式发送请求,但Rails API如果没有配置JSON API支持,会无法正确解析参数。

情况1:Rails使用JSON API格式

确保Rails项目安装了jsonapi-rails gem,并配置控制器处理JSON API参数:

# Gemfile
gem 'jsonapi-rails'

# app/controllers/scores_controller.rb
class ScoresController < ApplicationController
  include JSONAPI::ActsAsResourceController

  private
  def score_params
    params.require(:data).require(:attributes).permit(:wins, :losses, :draws, :username)
  end
end

情况2:Rails使用传统REST格式

如果Rails期望的是{ score: { wins: 56 } }这类参数,需要给Score模型添加REST序列化器:

// app/serializers/score.js
import RESTSerializer from '@ember-data/serializer/rest';

export default class ScoreSerializer extends RESTSerializer {
  serialize(snapshot, options) {
    let json = super.serialize(snapshot, options);
    // 把属性包裹在score键中,匹配Rails的参数要求
    return { score: json };
  }
}

同时对应的适配器保持REST风格:

// app/adapters/score.js
import RESTAdapter from '@ember-data/adapter/rest';

export default class ScoreAdapter extends RESTAdapter {
  host = 'http://localhost:3000';
}

4. 调试时检查请求细节

打开浏览器开发者工具的Network标签,查看PATCH请求的:

  • 请求URL是否正确(比如http://localhost:3000/scores/1)
  • 请求体中的参数是否是新值
  • 后端响应的状态码和内容(如果返回422,说明后端参数验证失败)

通过这些步骤,应该能解决你遇到的更新问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 14:22:35