【问题标题】:Updating rails has_many through relations通过关系更新 rails has_many
【发布时间】:2014-11-17 18:36:49
【问题描述】:

我有模型

class Agency < ActiveRecord::Base
  has_many :specializations
  has_many :cruise_lines, through: :specializations
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

我想更新Specialization 集合(即删除一些旧关系并在需要时添加一些新关系)。我应该更新关系的方法如下所示(在一些单独的服务中):

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

  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
  return false if agency.errors.present?
  true
end

但这基本上没有任何作用,但是,结合更新代理 - 这个确切的代码有效。我做错了什么?

在当前实现中,它发出错误ERROR: duplicate key value violates unique constraint "index_specializations_on_agency_id_and_cruise_line_id" DETAIL: Key (agency_id, cruise_line_id)=(1, 3) already exists.,这意味着它试图保存尚未删除旧关系的新关系,因此它违反了相同条目的索引。

【问题讨论】:

    标签: ruby-on-rails activerecord associations models


    【解决方案1】:

    第一个解决方案:

    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
      end
      !agency.errors.present?
    end
    

    简而言之,不要构建任何东西。让 Rails 完成这项工作。

    第二种解决方案:

    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
    

    这是您方法的扩展,应该可以完成这项工作。请注意,在这种情况下,所有specializations 首先被销毁,然后最终重建。

    【讨论】:

    • 完美!谢谢,你救了我的晚上! (顺便说一句,我也想在交易中做,但第一种方法更干净,很好)
    • 我应该把这个方法放在哪里?这应该在控制器中吗?此外,似乎应该在不同的控制器中改变,正确的方法名称是 update__
    猜你喜欢
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多