ActiveRecord在事务中保存无效模型,不进行回滚

时间:2014-11-24 16:21:21

标签: ruby-on-rails activerecord transactions

我有模特

class Agency < ActiveRecord::Base
  SPECIALIZATIONS_LIMIT = 5

  has_many :specializations
  has_many :cruise_lines, through: :specializations

  protected 

    def validate_specializations_limit
      errors.add(:base, "Agency specializations max limit is #{SPECIALIZATIONS_LIMIT}. Deselect some before saving.") if specializations.count > SPECIALIZATIONS_LIMIT
    end
end

class CruiseLine < ActiveRecord::Base
  has_many :specializations
  has_many :agencies, through: :specializations
end

class Specialization < ActiveRecord::Base
  belongs_to :agency, inverse_of: :specializations
  belongs_to :cruise_line, inverse_of: :specializations
end

更新代理商专业化的方法,如果代理商无效,则在保存数据时不会回滚(即使超出限制也会返回true)。这次交易有什么问题?

module SpecializationService
  def self.update_agency_specializations(agency, params)
    attributes = params.require(:agency).permit( { cruise_line_ids: [] } )

    persisted = true
    begin 
      Agency.transaction do 
        agency.specializations.destroy_all
        attributes[:cruise_line_ids].select{ |x| x.to_i > 0 }.each do |cruise_line_id|
          agency.specializations.build(cruise_line_id: cruise_line_id)
        end
        agency.save!
      end 
    rescue RecordInvalid => e
      persisted = false
    end
    persisted
  end
end

当我尝试保存这样的数据时(如果超出限制则返回false) - 它会显示错误的Flash消息,但无论如何都会保存关系,因此该代理无效。

module SpecializationService
  def self.update_agency_specializations(agency, params)
    attributes = params.require(:agency).permit( { cruise_line_ids: [] } )

    agency.cruise_line_ids = attributes[:cruise_line_ids].select{ |x| x.to_i > 0 }
    agency.save
    !agency.errors.present?
  end
end

保存专业化超过限制 - 代理商模式无法在其他页面上更新,因为它始终无效。

更新

我已查看agency.specializations.count

1)在交易之前它是正确的,代理是有效的(如果它确实是正确的,但表格包含太多的专业化要保存)。

2)在销毁专业并建立新专业后,他们的计数为0(为什么??),因此验证通过

3)超过保存计数后(如果我选择了太多),代理 - 无效。

1 个答案:

答案 0 :(得分:1)

不要使用.count,请使用.length。 count使用对数据库的调用,而length将检查内存中的对象。

有关计数/尺寸/长度的更多信息,请参阅此帖子: ActiveRecord: size vs count