2015-12-26 38 views
1

我有一個產品模型包含產品名稱和產品創建前隨機生成的唯一引用。我想用這兩個來產生一個frindly_id網址。這裏是我的嘗試:添加Rails的隨機唯一引用Friendly_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。似乎是當參考屬性仍然當代完成slu generation。當我將friendly_id :friendly_id_syntax, use: :slugged放在before_create之前時,結果相同。

有什麼想法嗎?

回答

2

從文檔here

FriendlyId使用before_validation回調來生成並設置 塞...

before_validationbefore_create之前運行。因此,要解決這個問題,改變before_createbefore_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 
+0

謝謝AbM,你說得對。現在它可以工作。 – htaidirt

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

有這幾個好處,包括您可以參考單個對象不管他們存儲在哪裏,並且 - 正如你所發現的那樣 - 使用uuid的能力就像一個slu。子彈。

你可以隨心所欲,我想實現一個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中使用它可能是粗略的;但最終可能會爲您提供您想要的功能。