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

发布于 2025-01-14 23:35:54 字数 2690 浏览 4 评论 0原文

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

我的问题是 - 是否有一种建议的方法可以实现相同的效果,无需添加 _attributes 即可在 RoR 上创建 emotion 对象数组服务器?我所说的建议要么是框架本身建议的东西,要么是尽可能干净的东西。

JSON 发布到 http://localhost:3000/periods:

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

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

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

我希望能够发布的是:

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

I've managed to get nested many-to-many entities created through the use of accepts_nested_attributes_for for the JSON and the project below.

My question is - is there a suggested way to achieve the same thing where I don't have to add _attributes to be able to create the array of emotion objects on the RoR server? What I mean by suggested is either something the framework itself suggests or otherwise something as clean as possible.

JSON getting posted to http://localhost:3000/periods:

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

rails generate commands used to create subsequent files:

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

What I'd like to be able to post is this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

生生漫 2025-01-21 23:35:54

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

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

但恕我直言,只要您刚刚开始使用 Rails 之旅,您就应该保留默认约定,并且主要关心的是“情感看起来比情感属性更好”。

you won't find the cleaner way to achieve that cause "emotions_attributes" are handled "out of the box" by the framework.

alternatively you can create an service object for more custom period creation (fe app/services/periods/create.rb) and call it from controller. This way you can customize default convention and keep the logic in one place.

But imho you should stay with the default convention as long as you are just starting your journey with rails and the main concern is that "emotions looks better than emotions_attributes".

为你鎻心 2025-01-21 23:35:54

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

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)

这是实现你的目标的一种方法,但是回答你的问题,没有建议的方法可以做到这一点。

Well, you could permit your params like this:

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

And then the first thing you could do in #create is:

# receive the permitted params
period_params = period_params_hand

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

This is a way to achieve your goal, but answering your question, there is no suggested way of doing that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文