是否有建议的方法在 RoR 中创建嵌套的多对多实体,避免嵌套资源的 JSON 字段中的 *_attributes?

Is there a suggested way to create nested many-to-many entities in RoR that avoids *_attributes in the JSON field for the nested resource?

我已经成功地通过使用 accepts_nested_attributes_for 为 JSON 和下面的项目创建了嵌套的多对多实体。

我的问题是 - 是否有建议的方法来实现相同的事情,我不必添加 _attributes 就能够在 RoR 服务器上创建 emotion 对象数组?我所说的建议的意思是框架本身建议的东西,或者尽可能干净的东西。

JSON 得到 posted 到 http://localhost:3000/periods:

{
    "period": {
        "date": "2022-03-17T03:00:52.820Z",
        "period": "morning",
        "emotions_attributes": [
            {
                "name": "ok"
            },
            {
                "name": "fine"
            }
        ]
    }
}

rails generate 用于创建后续文件的命令:

rails g model Emotion name:string
rails g scaffold Period date:date period:string --skip-template-engine
rails g scaffold Entry emotion:references period:references --skip-template-engine

periods.rb:

class Period < ApplicationRecord
  has_many :entries
  has_many :emotions, through: :entries

  accepts_nested_attributes_for :emotions
end

emotion.rb

class Emotion < ApplicationRecord
  has_many :entries
  has_many :periods, through: :entries
end

entry.rb

class Entry < ApplicationRecord
  belongs_to :emotion
  belongs_to :period
end

periods_controller.rb

class PeriodsController < ApplicationController
  before_action :set_period, only: %i[ show edit update destroy ]
  skip_before_action :verify_authenticity_token

  ...

  def create
    @period = Period.new(period_params)

    respond_to do |format|
      if @period.save
        format.html { redirect_to period_url(@period), notice: "Period was successfully created." }
        format.json { render :show, status: :created, location: @period }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @period.errors, status: :unprocessable_entity }
      end
    end
  end
  
  ...

    # FYI turns out the id is key here to be able to even perform create 
    def period_params
      params.require(:period).permit(
        :date, 
        :period,
        emotions_attributes: [:id, :name]
      )
    end

routes.rb

Rails.application.routes.draw do
  resources :entries
  resources :periods

我希望能够 post 是这样的:

{
    "period": {
        "date": "2022-03-17T03:00:52.820Z",
        "period": "morning",
        "emotions": [
            {
                "name": "ok"
            },
            {
                "name": "fine"
            }
        ]
    }
}

您不会找到实现该目标的更简洁方法,因为“emotions_attributes”由框架“开箱即用”处理。

或者,您可以创建一个服务对象以创建更多自定义周期 (fe app/services/periods/create.rb) 并从控制器调用它。这样您就可以自定义默认约定并将逻辑放在一个地方。

但是恕我直言,只要您刚刚开始使用 rails 并且主要担心的是“情绪看起来比 emotions_attributes 更好”,您就应该保持默认约定。

好吧,你可以像这样允许你的参数:

def period_params_hand
  params.require(:period).permit(
    :date, 
    :period,
    emotions: [:id, :name]
  )
end

然后您可以在#create 中做的第一件事是:

# receive the permitted params
period_params = period_params_hand

# rename the hash key
period_params[:emotions_attributes] = period_params.delete(:emotions)

这是实现您的目标的一种方法,但回答您的问题时,没有建议的方法。