Ruby on rails Rails 5.2中的ActiveRecord:save/update不保存记录,即使它说保存了
在ruby 2.6.5、postgres 10.11和pg gem 1.1.4版的Rails 5.2.4.1应用程序中,我有一个如下的ActiveRecord模型:Ruby on rails Rails 5.2中的ActiveRecord:save/update不保存记录,即使它说保存了,ruby-on-rails,ruby,postgresql,activerecord,ruby-on-rails-5,Ruby On Rails,Ruby,Postgresql,Activerecord,Ruby On Rails 5,在ruby 2.6.5、postgres 10.11和pg gem 1.1.4版的Rails 5.2.4.1应用程序中,我有一个如下的ActiveRecord模型: class房地产{select(RealEstate.column_names.map!(&:to_sym)-[:metadata]) 作用域:活动,->{where(活动:true)} 有_many:lots,->{where(lot:true)},类名:'realstate',外键:'program\u id' 属于:程序,类名
class房地产{select(RealEstate.column_names.map!(&:to_sym)-[:metadata])
作用域:活动,->{where(活动:true)}
有_many:lots,->{where(lot:true)},类名:'realstate',外键:'program\u id'
属于:程序,类名:'realstate',可选:true
枚举旧的或新的:{
老:0,,
新#U大厦:1#开发商新房地产项目
}
枚举事务类型:{
租金:0,,
购买:1
}
枚举属性\u类别:{
公寓:0,
众议院:1,
其他:2
}
结束
db/structure.sql
中的底层数据模型如下(某些列匿名):
正如您所看到的,没有Rails回调。“奇怪之处”——我们使用一个postgres JSONB列和一个postgres integer数组列
现在我们有了一个管理员更新路径来编辑其中的一些记录。它不遵循命名约定,也不使用活动记录验证,而是使用干式验证:
require 'dry-validation'
module Admin
class NewRealEstatesController < Admin::BaseController
before_action :set_form, only: [:edit, :update]
def update
validation_result = AdminRealEstateSchema.call(real_estate_listing_params.to_h)
if validation_result.success?
# Don't mind column mappings with the dry schema validator, there might be inconsistencies
# because I anonymized the column names, but the mapping is correct and validations pass
@estate.some_string_1 = params[:real_estate][:some_string_1]
@estate.some_string_2 = params[:real_estate][:some_string_2]
@estate.some_string_3 = params[:real_estate][:some_string_3]
@estate.property_category = params[:real_estate][:property_category]
@estate.some_string_4 = params[:real_estate][:some_string_4]
@estate.price = params[:real_estate][:price]
@estate.some_string_5 = params[:real_estate][:some_string_5]
@estate.active = params[:real_estate][:active]
@estate.some_timestamp_1 = params[:real_estate][:some_timestamp_1]
@estate.some_timestamp_2 = params[:real_estate][:some_timestamp_2]
@estate.some_count = params[:real_estate][:some_count]
@estate.surface = params[:real_estate][:surface]
@estate.some_boolean_1 = params[:real_estate][:some_boolean_1]
@estate.some_boolean_2 = params[:real_estate][:some_boolean_2]
res = @estate.save
render json: { result: 'done', debug: { res_save_ar: res, changed: @estate.saved_changes?, \
changes: @estate.saved_changes, previous_changes: @estate.previous_changes } }, status: 200
else
respond_to do |format|
format.html { render :edit }
format.json { render json: { errors: validation_result.errors.map{|key, error| "#{key} : #{error[0]}"} }, \
status: :unprocessable_entity, serializer: nil }
end
end
end
def edit; end
private
def set_form
@estate = RealEstate.find(params[:id])
end
def real_estate_listing_params
params[:real_estate_listing].permit(...) # all strong params edited in route, it's correct
end
end
end
AdminRealEstateSchema = Dry::Validation.Form do
configure { config.type_specs = true, config.messages = :i18n }
PROPERTY_CATEGORIES = %w(house apartment other)
required(:property_category, :string).filled(:str?, included_in?: PROPERTY_CATEGORIES)
required(:some_string_1, :string).filled(:str?)
required(:some_string_2, :string).filled
optional(:some_string_3).maybe(:str?)
optional(:some_string_4).maybe(:str?)
optional(:some_string_4).maybe(:str?)
optional(:some_string_5).maybe(:str?)
required(:price, :int).filled(:int?)
optional(:some_other_int).maybe(:int?)
optional(:some_count).maybe(:int?)
required(:active, :bool).filled(:bool?)
required(:some_boolean_1, :bool).filled(:bool?)
required(:some_boolean_2, :bool).filled(:bool?)
required(:some_time_1, :date_time).filled(:date_time?)
optional(:some_time_2).maybe(:date_time?)
end
要求“干式验证”
模块管理员
类NewRealEstatesController
视图是正确的,使用remote:true
现在谈谈这个问题:有时,由于表单的存在,记录会被保存和更新,但没有一致性,有时绝对不会保存和更新,就像更改已被回滚一样,即使save
返回true,如web控制台中返回的JSON所示
ActiveRecord还可以正确地映射所有应使用正确值更新/保存的列,如@estate.saved\u changes
Rspec测试全部通过。但只有在生产中,我们才会遇到这种错误
现在需要注意的几点可能很重要:
- 几个月前,我们已经遇到了一个
create\u或
bug。无法正确创建记录。迫于最后期限,我通过
求助于原始SQL,结果一切正常ActiveRecord::Base.connection.execute
- 此表非常活跃,有许多后台作业插入/读取客户的数据
- 此表上没有自定义postgres触发器
activerecord
中的一个bug
有什么想法吗 我相信这可能与最新稳定版本中的一个已知错误有关。我会和其他一些与pg开放相关的问题一起检查。我在使用pg数据类型时遇到了类似的情况,这些数据类型不是rails默认的int和string值(使用JSONB和Money)。我们是n
require 'dry-validation'
module Admin
class NewRealEstatesController < Admin::BaseController
before_action :set_form, only: [:edit, :update]
def update
validation_result = AdminRealEstateSchema.call(real_estate_listing_params.to_h)
if validation_result.success?
# Don't mind column mappings with the dry schema validator, there might be inconsistencies
# because I anonymized the column names, but the mapping is correct and validations pass
@estate.some_string_1 = params[:real_estate][:some_string_1]
@estate.some_string_2 = params[:real_estate][:some_string_2]
@estate.some_string_3 = params[:real_estate][:some_string_3]
@estate.property_category = params[:real_estate][:property_category]
@estate.some_string_4 = params[:real_estate][:some_string_4]
@estate.price = params[:real_estate][:price]
@estate.some_string_5 = params[:real_estate][:some_string_5]
@estate.active = params[:real_estate][:active]
@estate.some_timestamp_1 = params[:real_estate][:some_timestamp_1]
@estate.some_timestamp_2 = params[:real_estate][:some_timestamp_2]
@estate.some_count = params[:real_estate][:some_count]
@estate.surface = params[:real_estate][:surface]
@estate.some_boolean_1 = params[:real_estate][:some_boolean_1]
@estate.some_boolean_2 = params[:real_estate][:some_boolean_2]
res = @estate.save
render json: { result: 'done', debug: { res_save_ar: res, changed: @estate.saved_changes?, \
changes: @estate.saved_changes, previous_changes: @estate.previous_changes } }, status: 200
else
respond_to do |format|
format.html { render :edit }
format.json { render json: { errors: validation_result.errors.map{|key, error| "#{key} : #{error[0]}"} }, \
status: :unprocessable_entity, serializer: nil }
end
end
end
def edit; end
private
def set_form
@estate = RealEstate.find(params[:id])
end
def real_estate_listing_params
params[:real_estate_listing].permit(...) # all strong params edited in route, it's correct
end
end
end
AdminRealEstateSchema = Dry::Validation.Form do
configure { config.type_specs = true, config.messages = :i18n }
PROPERTY_CATEGORIES = %w(house apartment other)
required(:property_category, :string).filled(:str?, included_in?: PROPERTY_CATEGORIES)
required(:some_string_1, :string).filled(:str?)
required(:some_string_2, :string).filled
optional(:some_string_3).maybe(:str?)
optional(:some_string_4).maybe(:str?)
optional(:some_string_4).maybe(:str?)
optional(:some_string_5).maybe(:str?)
required(:price, :int).filled(:int?)
optional(:some_other_int).maybe(:int?)
optional(:some_count).maybe(:int?)
required(:active, :bool).filled(:bool?)
required(:some_boolean_1, :bool).filled(:bool?)
required(:some_boolean_2, :bool).filled(:bool?)
required(:some_time_1, :date_time).filled(:date_time?)
optional(:some_time_2).maybe(:date_time?)
end