How to create sequential unique identifier for db field

I have a Slug table with a unique field url.

If i create @slug = Slug.url = "foo"

When I go to save if Slug.url from "foo" already exists, I would then try Slug.url from "foo-1", if it also exists, try "foo-2" foo-3, foo- 4 etc. Until a value is found that does not exist and can be created in db ... What will be the correct way to do this in my rail model?

thank

UPDATE:

My last code is as follows:

  def set_url
    self.url = self.title.parameterize
    # Ensure the url is available
    qUrl = self.url.split('-').shift
    slugs = Slug.where("url like '#{qUrl}%'")
    if slugs.exists?
      c = slugs.count + 1
      self.url = self.url + "-" + c.to_s
    end
  end

, qUrl , , "", . - .

+4
5

Rails , Slug, URL- slug-URL, :

1.

friendly_id sequentially_slugged , ( , before_validation.

Rails :

rails new .

friendly_id Gemfile ( bundle install ):

gem 'friendly_id'

slugs ( rake db:migrate after), db/migrate/20170114211811_create_slugs.rb:

class CreateSlugs < ActiveRecord::Migration
  def change
    create_table :slugs do |t|
      t.string :url
      t.string :title
    end
    add_index :slugs, :url, unique: true
    add_reference :slugs, :item, polymorphic: true, index: true
  end
end

Slug, friendly_id, app/models/slug.rb:

class Slug < ActiveRecord::Base
  extend FriendlyId
  friendly_id :title,
    use: :sequentially_slugged,
    slug_column: :url
  belongs_to :item, polymorphic: true
end

2. +

(, /this-is-my-x).

config/routes.rb:

Rails.application.routes.draw do
  get ':url' => 'slugs#show'
end

Slug, Slug render , Slug Model.

app/controllers/slugs_controller.rb:

class SlugsController < ApplicationController
  def show
    @item = Slug.find_by(url: params[:url])
    render "#{@item.item_type.pluralize.underscore}/show"
  end
end

3. Sluggable Models + Views

, Slug .

Article + :

rails generate model article title:string

app/models/article.rb:

class Article < ActiveRecord::Base
  has_one :slug, as: :item
  before_validation do
    if slug.try(:title) != title
      self.slug = Slug.create(title: title)
    end
  end
end

app/views/articles/show.html.erb:

<h1>Articles#show</h1>
<p>Title is <%=@item.title%>, ID is <%=@item.id%></p>

+ , ..

4.

rails console:

(1..10).each { Article.create title: 'foo' }

( rails server localhost:3000/foo-7):

Articles#show
Title is foo, ID is 7

!

+2

friendly_id gem . , , , uuid slug .

, .

+4

before_save ( , ):

Slug

before_save :check_and_generate_unique_slug

private

def check_and_generate_unique_slug
  is_unique = Slug.where(url: self.url).count > 0 ? false : true

  unless is_unique
    #if say previous url was foo-1, self.url.last.to_i gives 1
    new_url = "foo-#{self.url.last.to_i + 1}" #here it foo-2
    self.url = new_url
    self.check_and_generate_unique_slug
  else
    self.url = new_url
  end
end

URL- "foo", "foo".last.to_i 0, url foo - # {0 + 1} = foo-1

def check_and_generate_unique_slug
  urls = Slug.pluck(:url).uniq
  #=> ["foo", "foo-1", "foo-3", "foo-2"]

  latest_url_code = urls.map{|a| a.last.to_i}.uniq.sort.last
  #=> urls.map{|a| a.last.to_i}.uniq.sort  gives  [0, 1, 2, 3]
  #=> last will give 3

  self.url = "foo-#{latest_url_code + 1}"
end

As mentioned in the comment last could be a 2 digit

The code can be changed as: "foo-xxx".split("-").last.to_i

+1
source

try it

before_save :generate_slug

private

def genareate_slug
  url = self.name.to_s.parameterize(title)
  count = Slug.where("url LIKE '#{url}'").count
  self.url = count.positive? ? "#{url}-#{count + 1}" : url
end
+1
source

Try the following:

class Slug < ActiveRecord::Base     

  before_validation :set_slug, :on => :create

  protected 

  def set_slug
    tmp = "#{ title.downcase.gsub(/[^a-z0-9]+/i, '-') }"
    i = 0
    self.url = loop do
      tmp.concat("-#{ i }") if i > 0
      i += 1
      break tmp unless Slug.exists?(url: tmp)
    end
  end

end

try in the console.

tmp1 = Slug.create!(title: 'hello world')
tmp1.url #=> "hello-world"

tmp2 = Slug.create!(title: 'Hello World')
tmp2.url #=> "hello-world-1"
+1
source

Source: https://habr.com/ru/post/1665825/


All Articles