添加对Rails Friendly_id虚荣URL的随机唯一引用

时间:2015-12-26 07:59:29

标签: ruby-on-rails friendly-id

我有一个产品模型,其中包含产品名称和在产品创建之前随机生成的唯一引用。我想使用它们来生成frindly_id URL。这是我的尝试:

# == Schema Information
#
# Table name: products
#
#  name        :string           not null
#  slug        :string
#  reference   :string
#
class Product < ActiveRecord::Base
  extend FriendlyId

  before_create :generate_unique_reference
  friendly_id :friendly_id_syntax, use: :slugged

  def generate_unique_reference
    self.reference = SecureRandom.hex(3).upcase
  end

  def friendly_id_syntax
    [
      [:name, :reference]
    ]
  end
end

这将生成仅包含产品名称的虚荣URL(不包含产品参考)。似乎在引用属性仍为 nil 时完成了slug生成。当我将friendly_id :friendly_id_syntax, use: :slugged放在before_create之前时,我得到了相同的结果。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

来自文档here

  

FriendlyId使用before_validation回调来生成和设置   蛞蝓...

before_validationbefore_create之前运行。要解决此问题,请将before_create更改为before_validation

class Product < ActiveRecord::Base
  extend FriendlyId

  before_validation :generate_unique_reference, on: :create
  friendly_id :friendly_id_syntax, use: :slugged

  def generate_unique_reference
    self.reference = SecureRandom.hex(3).upcase
  end

  def friendly_id_syntax
    [
      [:name, :reference]
    ]
  end
end

答案 1 :(得分:0)

另一种方法是使用slug_candidates(虽然我不认为它会提供你想要的确切功能):

#app/models/product.rb
class Product < ActiveRecord::Base
   extend FriendlyID
   friendly_id :slug_candidates, use: :slugged

   def reference
      SecureRandom.hex(3).upcase
   end

   private

   def slug_candidates
      [
        [:name, :reference]
      ]
   end
end

好的,我刚刚意识到这正是你已经完成的事情。如果有人想看到对问题的另一种解释,我仍会发布答案;如有必要,我会删除。

可能希望考虑的其他内容是在您的数据库中实施uuid

  

通用唯一标识符(UUID)是软件构造中使用的标识符标准。 UUID只是一个128位的值。每个位的含义由几种变体中的任何一种定义。

大多数人会因为提出这个问题而将我分开;您必须使用以下字符串替换id主键:de305d54-75b4-431b-adb2-eb6b9e546014

我们用一些东西来做:

enter image description here

这有几个好处,包括您可以引用单个对象,无论它们存储在何处,并且 - 正如您所发现的那样 - 能够在诸如slug之类的东西中使用uuid

你可以随心所欲;我实施了uuid,然后friendly_id更新after_create

#app/models/product.rb
class Product < ActiveRecord::Base
   extend FriendlyID
   friendly_id :slug_candidates, use: :slugged

   after_create :set_new_friendly_id

   private

   def slug_candidates
      [
        [:name, :uuid]
      ]
   end

   def set_new_friendly_id
      self.save #-> I know a double SQL call, but only way to get UUID
   end

   def should_generate_new_friendly_id?
      uuid.present? #-> only updates if uuid is present
   end
end

要使uuid正常工作,您必须使用MYSQL中的uuid()函数或PGSQL中的uuid_generate_v4函数:

# db/schama.rb
create_table "nodes", force: :cascade, id: false do |t|
    t.string   "uuid",        limit: 255, default: (Rails.env.staging? ? "uuid_generate_v4();" : 0), null: false
    t.string   "type",        limit: 255
    t.string   "slug",        limit: 255
    t.string   "title",       limit: 255
    t.text     "value",       limit: 65535
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
end

  execute "ALTER TABLE nodes ADD PRIMARY KEY (uuid);"
  if Rails.env.staging? #-> Heroku PGSQL
    execute("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"")
  else
    execute("DROP TRIGGER IF EXISTS before_insert_nodes;") #http://stackoverflow.com/a/5945220/1143732
    execute("CREATE TRIGGER before_insert_nodes BEFORE INSERT ON nodes FOR EACH ROW SET new.uuid = uuid();")
  end

虽然这会使UUID代从应用程序逻辑中删除,但这意味着您只能在创建记录后使用UUID 。这就是为什么在friendly_id中使用它可能会很粗略;但最终可能会为您提供您想要的功能。