# frozen_string_literal: true require "set_as_primary/version" require "active_support/concern" module SetAsPrimary class Error < StandardError; end extend ActiveSupport::Concern included do before_save :unset_old_primary before_save :force_primary, if: -> { self.class._force_primary } instance_eval do class_attribute :_primary_flag_attribute, :_owner_key, :_force_primary def set_as_primary(primary_flag_attribute = :primary, options) configuration = { owner_key: nil, force_primary: true } configuration.update(options) if options.is_a?(Hash) handle_setup_errors(primary_flag_attribute, configuration) self._primary_flag_attribute = primary_flag_attribute self._owner_key = configuration[:owner_key] self._force_primary = configuration[:force_primary] end private def handle_setup_errors(primary_flag_attribute, configuration) if !primary_flag_attribute.is_a?(Symbol) raise SetAsPrimary::Error, "Wrong attribute! Please provide attribute in symbol type." end owner_key = configuration[:owner_key] if owner_key.nil? raise SetAsPrimary::Error, "Please provide `owner_key` option." end if reflect_on_association(owner_key).nil? raise ActiveRecord::AssociationNotFoundError.new(self, owner_key) end end end end private def unset_old_primary return unless self.public_send(self.class._primary_flag_attribute) scope = self.class.where(scope_options) scope = scope.where("id != ?", id) unless new_record? scope.update_all(self.class._primary_flag_attribute => false) end def force_primary count = self.class.where(scope_options).count if (count == 1 && !new_record?) || (count == 0 && new_record?) self.public_send("#{self.class._primary_flag_attribute}=", true) end end def scope_options if self.class.reflect_on_association(self._owner_key).options[:polymorphic] polymorphic_condition_options else owner_id = "#{self.class._owner_key}_id".to_sym { owner_id => self.public_send(owner_id) } end end def polymorphic_condition_options owner = self.public_send(self.class._owner_key) { "#{self.class._owner_key}_id".to_sym => owner.id, "#{self.class._owner_key}_type".to_sym => owner.class.name } end end