0

I have models

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

And method updating agency specializations that does no rollback when saving data if agency is invalid (returns true even if limit is exceeded). What is wrong with this transaction?

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

When I try to save data like this (returns false if limit exceeded) - it shows error flash message, but relations are saved anyways, so that agency is again invalid.

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

After saving specializations over limit - agency model can not be updated on other pages, because it is always invalid.

Update

I've checked agency.specializations.count:

1) before transaction it is correct, agency is valid (if it is really correct, but form contains too much specializations to save).

2) after destroying specializations and building new ones their count is 0 (why??), so validation passes

3) after saving count is exceeded (if I selected too many), agency - invalid.

kovpack
  • 4,905
  • 8
  • 38
  • 55
  • 1
    `specializations.count` seems to be unreliable if the model is unsaved and associated objects are altered. Try inspecting what value is this during validation: it might actually show something valid, save it and this way make it invalid. – D-side Nov 24 '14 at 16:25
  • I've updated comment on `count`. It turned out, after build count is `0` :( maybe, `inverse_of` is incorrect somewhere? – kovpack Nov 24 '14 at 16:44

1 Answers1

1

Don't use .count, use .length. count uses a call to the database, while length will check the object in memory.

See this post for more about count/size/length: ActiveRecord: size vs count

Community
  • 1
  • 1
harabbi
  • 66
  • 2