有没有一种建议的方法可以在 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?

提问人:foamroll 提问时间:3/17/2022 最后编辑:foamroll 更新时间:3/17/2022 访问量:69

问:

我已经设法通过使用 for JSON 和下面的项目创建了嵌套的多对多实体。accepts_nested_attributes_for

我的问题是 - 有没有一种建议的方法可以实现同样的事情,我不必添加就可以在 RoR 服务器上创建对象数组?我所说的建议要么是框架本身所建议的,要么是尽可能干净的东西。_attributesemotion

JSON 被发布到 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

句点.rb

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

  accepts_nested_attributes_for :emotions
end

情感.rb

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

条目.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

路由.rb

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

我希望能够发布的是:

{
    "period": {
        "date": "2022-03-17T03:00:52.820Z",
        "period": "morning",
        "emotions": [
            {
                "name": "ok"
            },
            {
                "name": "fine"
            }
        ]
    }
}
ruby-on-rails 对多 嵌套属性 accepts-nested-attributes

评论


答:

1赞 res 3/17/2022 #1

你不会找到更简洁的方法来实现这一点,因为“emotions_attributes”是由框架“开箱即用”地处理的。

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

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

评论

0赞 foamroll 3/21/2022
在 Virtus gem 的帮助下,如果 *_attributes 是不可取的,那么这样的事情将是要走的路
0赞 Ruan Lopes de Andrade 3/17/2022 #2

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

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)

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

评论

0赞 foamroll 3/21/2022
这没有用。我想它只会改变服务器端的参数,一旦它们进来了?