Updating rails has_many through relations

戏子无情 提交于 2019-12-11 04:06:51

问题


I have models

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

I want to update Specialization collection (that is delete some of old relations and add a few new if needed). My method that should update relations looks like this (inside some separate service):

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

But this does basically nothing, however, in combination with updating agency - this exact code worked. What am I doing wrong?

In current implementation it issues error 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. So that means that it tries to save new relations having not yet deleted old ones, so it violates index of entries that are the same.


回答1:


First solution:

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

In short, don't build anything. Let Rails do the job.

Second solution:

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

It is the extension of your approach and should do the job. Note that in this case all specializations are destroyed first and then rebuild eventually.



来源:https://stackoverflow.com/questions/26979515/updating-rails-has-many-through-relations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!