调用 ActiveRecord#find_or_create_by 时如何修复错误 ActiveRecord::RecordNotSaved
How to fix Error ActiveRecord::RecordNotSaved when calling ActiveRecord#find_or_create_by
我在网站上工作,每当有人忘记表单中的空字段时,我都会收到一条错误消息
You cannot call create unless the parent is saved
这是痕迹:
Application Trace
app/views/technicians/offer_comments/_offer_comment.html.slim:1:in `_app_views_technicians_offer_comments__offer_comment_html_slim__1148413763742950523_70319840794240'
app/views/offer_comments/index.html.slim:2:in `_app_views_offer_comments_index_html_slim___917297770217289302_70319839456700'
app/views/shared/offers/_comments.html.slim:8:in `_app_views_shared_offers__comments_html_slim__3779418887197040636_70319839163900'
app/views/technicians/auctions/show.html.slim:98:in `block in _app_views_technicians_auctions_show_html_slim___1454306351028108654_70319829646100'
app/helpers/application_helper.rb:14:in `rescue in cache'
app/helpers/application_helper.rb:6:in `cache'
app/views/technicians/auctions/show.html.slim:1:in `_app_views_technicians_auctions_show_html_slim___1454306351028108654_70319829646100'
app/controllers/technicians/offers_controller.rb:54:in `update'
错误出现在这个html.slim
视图的第一行:
- offer_comment.read_receipts.find_or_create_by user: current_user
.comment id="offer-#{offer_comment.offer_id}-comment-#{offer_comment.id}"
.by
- if offer_comment.user == current_user
= t ".you"
- else
= t ".not_you"
= " - "
= t '.date', date: time_ago_in_words(offer_comment.created_at)
.content
= raw markdown offer_comment.content
有趣的是,这个错误只发生在我调用另一个对象时,offers
,在呈现先前代码的主视图中:show.html.slim
(最后一行)
ul#customer-auction-tabs.tabs.clean.collapse(data-tabs)
a#auctions-tabs-chevron href="#"
i#auctions-tabs-chevron-icon.fas.fa-chevron-up
li.tabs-title class=chat_active_class
a#chat-tab href="#chat" aria-selected="true"= t '.tabs.chat'
li.tabs-title class=offer_active_class
a#offers-tab href="#offers"= t '.tabs.offer'
- if comments_count > 0
li.tabs-title class=comments_active_class
a#comments-tab href="#comments"= t '.tabs.comments'
li.tabs-title class=other_active_class
a#other-tab href="#other"= t '.tabs.other'
.auctions.tabs-content data-tabs-content="customer-auction-tabs"
#chat.tabs-panel class=chat_active_class
= render partial: "shared/auctions/chat", locals: { auction: auction }
#offers.tabs-panel class=offer_active_class
= render partial: "shared/offers/new", locals: { offer: offer }
#comments.tabs-panel class=comments_active_class
= render partial: 'shared/offers/comments', locals: { offer: offer }
#other.tabs-panel class=other_active_class
- if auction.offers.count.zero?
= t "ingen andre bud endnu"
= render "shared/offers/other"
.offers= render offers
我不明白它是如何工作的,因为 find_or_create_by
显然应该可以工作,即使对象没有被保存。
谁能帮我解决这个问题,最好完全避免在视图中使用像 find_or_create_by
这样的逻辑?
这是优惠模型的一部分:
class Offer < ApplicationRecord
has_paper_trail
belongs_to :auction, -> { with_deleted }, counter_cache: true, touch: true
belongs_to :technician, counter_cache: true, foreign_key: :technician_id
has_one :settings, through: :technician
has_many :comments, -> { order(created_at: :asc) }, class_name: "OfferComment"
has_one :review, as: :target
delegate :rating, to: :review, allow_nil: true
delegate :rating_date, to: :review, allow_nil: true
delegate :rating_comment, to: :review, allow_nil: true
validates :description, presence: true
validates :cents, presence: true, numericality: { only_integer: true, greater_than: 0 }
validate :amount_validity
scope :not_by, ->(technician) { where.not(technician: technician) }
这也是在使用空字段更新表单时调用的控制器更新操作:
class Technicians::OffersController < Technicians::ApplicationController
rescue_from ActiveRecord::RecordNotFound do
render "technicians/auctions/lost", status: 404
end
def update
offer.attributes = offer_params
changed = offer.changed?
if offer.save
OfferUpdatedWorker.perform_async offer.id if changed
flash[:info] = t(".success")
redirect_to [:technicians, auction]
else
flash.now[:error] = t(".failure")
render "technicians/auctions/show",
locals: { auction: auction, offer: offer },
status: 400
end
end
另一个需要注意的重要文件是最初调用“technicians/auctions/show”的拍卖控制器
def show
render(:lost) && return if lost?
render :show, locals: {
offers: sorted_o,
auction: auction,
#other: other,
offer: offer,
} if stale? **cache_options(auction.id, auction.updated_at)
end
private
#=begin
def sorted_o
@sorted_o ||= begin
field = (%w[cheapest closest guarantee] & [params[:sort]])[0].presence || "cheapest"
case field
when "closest"
auction
.offers
.includes(:auction, :technician, :review)
.sort_by { |o| distance(o.technician, auction) }
when "guarantee"
auction
.offers
.includes(:auction, :technician, :review)
.joins(:settings)
.order("technician_settings.guarantee desc")
else
auction
.offers
.includes(:auction, :technician, :review)
.order(cents: :asc)
end
end
end
#=end
def offer
@offer ||= auction.offers.by(current_user) ||
auction.offers.new(technician: current_user)
end
看起来您需要先保存 offer_comment
,然后才能创建属于它的 read_receipt,这是有道理的 - offer_comment 直到已保存。
这可能会让您解决问题。
offer_comment.tap(&:save).read_receipts.find_or_create_by user: current_user
我修好了。问题的原因是当 update
操作在 offers_controller.rb
中失败时它调用没有 offers
变量的 show
视图,这个变量在某种程度上与 offer_comments
,但我不确定 how/why 因为 offer_comments
应该只与变量 offer
而不是 offers
.
但是,当我检查控制台时 offer_comments 中有空元素,所以我继续将视图更改为仅显示非空元素,然后错误堆栈指向 offers
未在 show
视图中定义。
我在网站上工作,每当有人忘记表单中的空字段时,我都会收到一条错误消息
You cannot call create unless the parent is saved
这是痕迹:
Application Trace
app/views/technicians/offer_comments/_offer_comment.html.slim:1:in `_app_views_technicians_offer_comments__offer_comment_html_slim__1148413763742950523_70319840794240'
app/views/offer_comments/index.html.slim:2:in `_app_views_offer_comments_index_html_slim___917297770217289302_70319839456700'
app/views/shared/offers/_comments.html.slim:8:in `_app_views_shared_offers__comments_html_slim__3779418887197040636_70319839163900'
app/views/technicians/auctions/show.html.slim:98:in `block in _app_views_technicians_auctions_show_html_slim___1454306351028108654_70319829646100'
app/helpers/application_helper.rb:14:in `rescue in cache'
app/helpers/application_helper.rb:6:in `cache'
app/views/technicians/auctions/show.html.slim:1:in `_app_views_technicians_auctions_show_html_slim___1454306351028108654_70319829646100'
app/controllers/technicians/offers_controller.rb:54:in `update'
错误出现在这个html.slim
视图的第一行:
- offer_comment.read_receipts.find_or_create_by user: current_user
.comment id="offer-#{offer_comment.offer_id}-comment-#{offer_comment.id}"
.by
- if offer_comment.user == current_user
= t ".you"
- else
= t ".not_you"
= " - "
= t '.date', date: time_ago_in_words(offer_comment.created_at)
.content
= raw markdown offer_comment.content
有趣的是,这个错误只发生在我调用另一个对象时,offers
,在呈现先前代码的主视图中:show.html.slim
(最后一行)
ul#customer-auction-tabs.tabs.clean.collapse(data-tabs)
a#auctions-tabs-chevron href="#"
i#auctions-tabs-chevron-icon.fas.fa-chevron-up
li.tabs-title class=chat_active_class
a#chat-tab href="#chat" aria-selected="true"= t '.tabs.chat'
li.tabs-title class=offer_active_class
a#offers-tab href="#offers"= t '.tabs.offer'
- if comments_count > 0
li.tabs-title class=comments_active_class
a#comments-tab href="#comments"= t '.tabs.comments'
li.tabs-title class=other_active_class
a#other-tab href="#other"= t '.tabs.other'
.auctions.tabs-content data-tabs-content="customer-auction-tabs"
#chat.tabs-panel class=chat_active_class
= render partial: "shared/auctions/chat", locals: { auction: auction }
#offers.tabs-panel class=offer_active_class
= render partial: "shared/offers/new", locals: { offer: offer }
#comments.tabs-panel class=comments_active_class
= render partial: 'shared/offers/comments', locals: { offer: offer }
#other.tabs-panel class=other_active_class
- if auction.offers.count.zero?
= t "ingen andre bud endnu"
= render "shared/offers/other"
.offers= render offers
我不明白它是如何工作的,因为 find_or_create_by
显然应该可以工作,即使对象没有被保存。
谁能帮我解决这个问题,最好完全避免在视图中使用像 find_or_create_by
这样的逻辑?
这是优惠模型的一部分:
class Offer < ApplicationRecord
has_paper_trail
belongs_to :auction, -> { with_deleted }, counter_cache: true, touch: true
belongs_to :technician, counter_cache: true, foreign_key: :technician_id
has_one :settings, through: :technician
has_many :comments, -> { order(created_at: :asc) }, class_name: "OfferComment"
has_one :review, as: :target
delegate :rating, to: :review, allow_nil: true
delegate :rating_date, to: :review, allow_nil: true
delegate :rating_comment, to: :review, allow_nil: true
validates :description, presence: true
validates :cents, presence: true, numericality: { only_integer: true, greater_than: 0 }
validate :amount_validity
scope :not_by, ->(technician) { where.not(technician: technician) }
这也是在使用空字段更新表单时调用的控制器更新操作:
class Technicians::OffersController < Technicians::ApplicationController
rescue_from ActiveRecord::RecordNotFound do
render "technicians/auctions/lost", status: 404
end
def update
offer.attributes = offer_params
changed = offer.changed?
if offer.save
OfferUpdatedWorker.perform_async offer.id if changed
flash[:info] = t(".success")
redirect_to [:technicians, auction]
else
flash.now[:error] = t(".failure")
render "technicians/auctions/show",
locals: { auction: auction, offer: offer },
status: 400
end
end
另一个需要注意的重要文件是最初调用“technicians/auctions/show”的拍卖控制器
def show
render(:lost) && return if lost?
render :show, locals: {
offers: sorted_o,
auction: auction,
#other: other,
offer: offer,
} if stale? **cache_options(auction.id, auction.updated_at)
end
private
#=begin
def sorted_o
@sorted_o ||= begin
field = (%w[cheapest closest guarantee] & [params[:sort]])[0].presence || "cheapest"
case field
when "closest"
auction
.offers
.includes(:auction, :technician, :review)
.sort_by { |o| distance(o.technician, auction) }
when "guarantee"
auction
.offers
.includes(:auction, :technician, :review)
.joins(:settings)
.order("technician_settings.guarantee desc")
else
auction
.offers
.includes(:auction, :technician, :review)
.order(cents: :asc)
end
end
end
#=end
def offer
@offer ||= auction.offers.by(current_user) ||
auction.offers.new(technician: current_user)
end
看起来您需要先保存 offer_comment
,然后才能创建属于它的 read_receipt,这是有道理的 - offer_comment 直到已保存。
这可能会让您解决问题。
offer_comment.tap(&:save).read_receipts.find_or_create_by user: current_user
我修好了。问题的原因是当 update
操作在 offers_controller.rb
中失败时它调用没有 offers
变量的 show
视图,这个变量在某种程度上与 offer_comments
,但我不确定 how/why 因为 offer_comments
应该只与变量 offer
而不是 offers
.
但是,当我检查控制台时 offer_comments 中有空元素,所以我继续将视图更改为仅显示非空元素,然后错误堆栈指向 offers
未在 show
视图中定义。