代码之家  ›  专栏  ›  技术社区  ›  DDAZZA

如何通过在rails中递增来保存唯一字符串?

  •  1
  • DDAZZA  · 技术社区  · 10 年前

    如何将唯一字符串保存到数据库中,如果该值存在,则将其递增。

    我所追求的行为类似于保存文件时的行为,例如foo.txt、foo1.txt

    我不想返回“非唯一值”错误消息。

    class Person < ActiveRecord::Base
      attr_accessible :name
    end
    
    Person.create(:name => 'Dave') # => 'Dave'
    Person.create(:name => 'Dave') # => 'Dave1'
    Person.create(:name => 'Dave') # => 'Dave2'
    

    我正在使用ruby、rails和mysql

    2 回复  |  直到 10 年前
        1
  •  0
  •   zauzaj    10 年前

    您不需要为模型设置验证唯一性。您可以使用以下内容:

    class Person < ActiveRecord::Base
     attr_accessible :name
     before_create :check_and_increment
    
    
     private
     def check_and_increment
       if Person.exists? name: self.name
         similar_persons = get_all_with_same_name self.name
         next_num = similar_persons.max_by{|m| m.scan(/\d+/)}.scan(/\d+/).first.nil? ? 1 : similar_persons.max_by{|m| m.scan(/\d+/)}.scan(/\d+/).first.to_i + 1
         self.name = "#{self.name}#{next_num}"
       else
         true
       end 
     end
    
     def get_all_with_same_name name
       where("name LIKE ?", 'name%')     
     end
    
    end
    

    这是解决问题的简单方法。例如,需要小心对待安娜和安娜斯塔西娅这样的人。这些人有不同的名字,但他们的名字是重叠的。

    希望这对你有所帮助。

        2
  •  0
  •   DDAZZA    10 年前

    我找不到任何rails或mysql特性来实现这一点,所以我创建了以下3个方法和

      def unique_name(name)                                                                                                                                                                                                                                                                                                   
        if Person.exists?(:name => name)                                                                                                                                                                                                                              
          generate_unique_name(name)                                                                                                                                                                                                                                                                                          
        else                                                                                                                                                                                                                                                                                                                  
          name                                                                                                                                                                                                                                                                                                                
        end                                                                                                                                                                                                                                                                                                                   
      end                                                                                                                                                                                                                                                                                                                     
    
      def similar_names(name)                                                                                                                                                                                                                                                                                                 
        Person.where("name LIKE ?", "#{name}%").pluck(:name)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
      end                                                                                                                                                                                                                                                                                                                     
    
      def generate_unique_name(name)                                                                                                                                                                                                                                                                                          
        number = similar_names(name).map{ |a| a.scan(/\d+$/).max.to_i }.compact.max.to_i + 1                                                                                                                                                                                                                                  
        "#{name} #{number}"                                                                                                                                                                                                                                                                                                   
      end   
    
      ...
    
      Person.create(:name => unique_name('Dave'))