Rails 3 app model how ensure only one boolean field set to true at a time

后端 未结 8 837
误落风尘
误落风尘 2021-01-31 11:37

I have a Logo model that has fields of name:string, default:boolean. I want the true value to be unique, so that only one item in the database can be set to true at once. How do

相关标签:
8条回答
  • 2021-01-31 11:55

    I also recommend falsifying all your records then making them true.

    add_column :users, :name ,:boolean, default: false
    
    0 讨论(0)
  • 2021-01-31 11:57
    class Model < ApplicationRecord
      before_save :ensure_single_default, if: :is_default?
    
      private
    
      def ensure_single_default
        self.class.update_all(is_default: false)
      end
    end
    

    You don't need to check the id because this callback happens before the truthy one is saved.

    0 讨论(0)
  • 2021-01-31 11:59

    I think it's good to check if the one you save is true before you falsify others. Otherwise you falsify everyone when you save a record that isn't active.

    def falsify_all_others
        if self.default
            self.class.where('id != ? and default', self.id).update_all("default = 'false'")
        end
    end
    
    0 讨论(0)
  • 2021-01-31 12:10

    This code is stolen from previous answer and slightly simplified:

    def falsify_all_others
      Item.where('id != ?', self.id).update_all("default = 'false'")
    end
    

    You can use this method in before_save callback in your model.

    Actually, it is better to "falsify" only records which values are 'true', like this:

    Item.where('id != ? and default', self.id).update_all("default = 'false'")
    

    UPDATE: to keep code DRY, use self.class instead of Item:

    self.class.where('id != ? and default', self.id).update_all("default = 'false'")
    
    0 讨论(0)
  • 2021-01-31 12:13

    If you're coming here in a more recent time and are using Rails 6, this should be covered on the database level as well as the model level:

    db level:

    add_index :items, :default, unique: true, where: '(default IS TRUE)', algorithm: :concurrently
    

    model level:

    class Item < ApplicationRecord
      scope :default, -> { where(default: true) }
    
      validates :default, uniqueness: { conditions: -> { default } }
    end
    
    0 讨论(0)
  • 2021-01-31 12:18

    if you want this to work for creating and updating (rails v4) make note of this tidbit from rails guides

    after_save runs both on create and update, but always after the more specific callbacks after_create and after_update, no matter the order in which the macro calls were executed.

    0 讨论(0)
提交回复
热议问题