更新Rails中的has_many through关系

3
我有模型。
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. 这意味着它试图保存新关系,而尚未删除旧关系,因此违反了相同条目的索引。
1个回答

8

第一解决方案:

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 都将首先被销毁,然后最终重建。


太棒了!谢谢,你救了我的晚上!(顺便说一句,我也想用事务来做,但第一种方法更简洁、更好) - kovpack
我应该把这个方法放在哪里?应该放在控制器里吗?另外,在不同的控制器中似乎需要进行更改,正确的方法名称是update_<model>_<associations>吗? - TimeString

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接