【问题标题】:How to create both a parent and nested elements at once with cocoon如何使用 cocoon 同时创建父元素和嵌套元素
【发布时间】:2018-08-02 19:24:19
【问题描述】:

我有一个Edition 模型,它接受Content 模型的嵌套属性。无论如何,我可以在创建新版本的同时创建嵌套内容。

创建版本时,它给了我错误:

Contents edition can't be blank

根据我的阅读,这是因为尚未创建版本,因此,没有edition_id可以进入目录。

我尝试在版本和内容模型中设置inverse_of 选项,但没有成功。我仍然收到此错误。

这是我的版本和内容模型:

class Content < ApplicationRecord
  validates_presence_of :heading, 
                        :link, 
                        :edition_id, 
                        :section_id

  belongs_to :edition, inverse_of: :contents
  belongs_to :section
  belongs_to :source, inverse_of: :contents
end

class Edition < ApplicationRecord
  validates_presence_of :date, :product_id

  belongs_to :product
  has_many :contents, dependent: :destroy, inverse_of: :edition
  has_many :sections, -> { distinct }, through: :contents

  accepts_nested_attributes_for :contents,
                                allow_destroy: true,
                                reject_if: lambda { |attrs| attrs['link'].blank? }
end

我该如何解决这个问题?

编辑:

创建版本时的服务器日志为:

Started POST "/editions" for 127.0.0.1 at 2018-08-02 15:47:49 +0530
Processing by EditionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"QqSMYoMC76mCLPc6LI2ZvAyDih99J6erizPr2+CzAmLDCx3GALccQdLqbDoNaPNza1UAm8m62a8uHQdTwHV3AQ==", "edition"=>{"date(1i)"=>"2018", "date(2i)"=>"8", "date(3i)"=>"1", "product_id"=>"1", "contents_attributes"=>{"1533205044547"=>{"_destroy"=>"false", "heading"=>"Heading 2", "body"=>"<p>Text 12</p>", "section_id"=>"1", "link"=>"https://www.example.com/heading_2", "top_story"=>"0"}}}, "files"=>"", "commit"=>"Create Edition"}
  User Load (1.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (1.2ms)  BEGIN
  Product Load (1.3ms)  SELECT  "products".* FROM "products" WHERE "products"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Source Load (1.0ms)  SELECT  "sources".* FROM "sources" WHERE "sources"."domain" = $1 ORDER BY "sources"."id" ASC LIMIT $2  [["domain", "www.example.com"], ["LIMIT", 1]]
  Section Load (0.9ms)  SELECT  "sections".* FROM "sections" WHERE "sections"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (1.5ms)  ROLLBACK

编辑 2:

EditionsController 创建动作和 edition_params 方法:

def create
  @edition = Edition.new(edition_params)

  respond_to do |format|
    if @edition.save
      format.html { redirect_to @edition, notice: 'Edition was successfully created.' }
      format.json { render :show, status: :created, location: @edition }
    else
      format.html { render :new }
      format.json { render json: @edition.errors, status: :unprocessable_entity }
    end
  end
end

def edition_params
  params.require(:edition).permit(:date, 
                                  :clicks, 
                                  :product_id,
                                  contents_attributes: [:id,
                                                        :heading,
                                                        :body,
                                                        :link,
                                                        :top_story,
                                                        :section_id,
                                                        :_destroy
                                                       ]
                                 )
end

【问题讨论】:

  • @JagdeepSingh 我已经用服务器日志编辑了问题
  • 添加了创建操作和用于它的参数,@JagdeepSingh :)
  • 试试下面给出的解决方案,让我知道以获得进一步的指导,如果对您有帮助,也请随时接受/投票。

标签: ruby-on-rails ruby-on-rails-5 cocoon-gem


【解决方案1】:

据我所知,您必须首先为nested attributes 构建对象,即

def new
  @edition = Edition.new
  contents = @edition.contents.build
end

create 行动中

def create
  @edition = Edition.new(edition_params)

  respond_to do |format|
    if @edition.save
      format.html { redirect_to @edition, notice: 'Edition was successfully created.' }
      format.json { render :show, status: :created, location: @edition }
    else
      format.html { render :new }
      format.json { render json: @edition.errors, status: :unprocessable_entity }
    end
  end
end

def edition_params
  params.require(:edition).permit(:date, 
                                  :clicks, 
                                  :product_id,
                                  contents_attributes: [:id,
                                                        :heading,
                                                        :body,
                                                        :link,
                                                        :top_story,
                                                        :section_id,
                                                        :_destroy
                                                       ]
                                 )
end

删除edition_id的验证

class Content < ApplicationRecord
  validates_presence_of :heading, 
                        :link, 
                        :section_id

  belongs_to :edition, inverse_of: :contents
  belongs_to :section
  belongs_to :source, inverse_of: :contents
end

【讨论】:

  • @edition.contents.build 将返回 content(单数)。
  • @JagdeepSingh 同意!但据我所知cocoon gem 自己处理我们想要创建的许多嵌套对象,但首先它需要提供一个构建嵌套对象。
  • 不,没用 :(。我不确定是内容问题。我认为只是版本尚未创建,所以没有@ 987654331@ 分配给嵌套内容。有没有办法创建版本然后创建内容?即按顺序创建它们?
  • @UmarGhouse 您能否检查更新的答案,正如我所见,您已在 rails 5 中添加了 content_id 验证存在为真,仅供参考,belongs_to :content 表示它也需要。从验证中删除它并重试,希望现在应该可以工作。
【解决方案2】:

您可以添加 optional: true 关联这将解决您的错误,就像这样

belongs_to :edition, optional: true

【讨论】:

  • Optional: true 这样很容易让创建没有父对象的子对象,这是不对的。
  • 是的,它可以很容易地让创建没有父对象的子对象,但这取决于要求,以防孩子并不总是需要父对象,您可以选择可选:true
  • 谢谢!但是,在我的情况下,父母是必需的。本质上,内容不应该没有版本。
  • 好的,那就不要使用 optional: true 如果需要 parent
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-16
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
相关资源
最近更新 更多