2016-04-14 26 views
2

我有三個型號:如何確保表不包含重複項(基於兩個外鍵)?

class Ingredient < ActiveRecord::Base 
    has_one :component 
end 

class Size < ActiveRecord::Base 
    has_one :component 
end 

class Component < ActiveRecord::Base 
    belongs_to :ingredient 
    belongs_to :size 
end 

schema.rb樣子:

ActiveRecord::Schema.define(version: 20160414202240) do 

    create_table "components", force: :cascade do |t| 
    t.boolean "active" 
    t.decimal "cost" 
    t.decimal "price" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    t.integer "size_id" 
    t.integer "ingredient_id" 
    end 

    add_index "components", ["ingredient_id"], name: "index_components_on_ingredient_id" 
    add_index "components", ["size_id"], name: "index_components_on_size_id" 

    create_table "ingredients", force: :cascade do |t| 
    t.string "name" 
    t.boolean "active" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    end 

    create_table "sizes", force: :cascade do |t| 
    t.string "name" 
    t.boolean "active" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    end 

end 

現在,我播種與數據庫:

size_small = Size.create(name: 'Small', active: true) 
size_medium = Size.create(name: 'Medium', active: true) 
size_large = Size.create(name: 'Large', active: true) 

ingredient_tomato = Ingredient.create(name: 'Tomato', active: true) 
ingredient_onion = Ingredient.create(name: 'Onion', active: true) 
ingredient_red_onion = Ingredient.create(name: 'Red onion', active: true) 
ingredient_champignons = Ingredient.create(name: 'Champignons', active: true) 
ingredient_shrimps = Ingredient.create(name: 'Shrimps', active: true) 

Component.create(cost: 0.20, price: 1.00, active: true, size: size_small, ingredient: ingredient_tomato) 
Component.create(cost: 0.20, price: 1.00, active: true, size: size_small, ingredient: ingredient_onion) 
Component.create(cost: 0.20, price: 1.00, active: true, size: size_small, ingredient: ingredient_red_onion) 
Component.create(cost: 0.30, price: 1.00, active: true, size: size_small, ingredient: ingredient_champignons) 
Component.create(cost: 0.50, price: 1.50, active: true, size: size_small, ingredient: ingredient_shrimps) 

Component.create(cost: 0.30, price: 1.50, active: true, size: size_medium, ingredient: ingredient_tomato) 
Component.create(cost: 0.30, price: 1.50, active: true, size: size_medium, ingredient: ingredient_onion) 
Component.create(cost: 0.30, price: 1.50, active: true, size: size_medium, ingredient: ingredient_red_onion) 
Component.create(cost: 0.45, price: 1.50, active: true, size: size_medium, ingredient: ingredient_champignons) 
Component.create(cost: 0.75, price: 2.25, active: true, size: size_medium, ingredient: ingredient_shrimps) 

Component.create(cost: 0.40, price: 2.00, active: true, size: size_large, ingredient: ingredient_tomato) 
Component.create(cost: 0.40, price: 2.00, active: true, size: size_large, ingredient: ingredient_onion) 
Component.create(cost: 0.40, price: 2.00, active: true, size: size_large, ingredient: ingredient_red_onion) 
Component.create(cost: 0.60, price: 2.00, active: true, size: size_large, ingredient: ingredient_champignons) 
Component.create(cost: 1.00, price: 3.00, active: true, size: size_large, ingredient: ingredient_shrimps) 

# This one uses again `size_small` and `ingredient_tomato` and shouldn't be allowed. 
Component.create(cost: 2.99, price: 7.99, active: true, size: size_small, ingredient: ingredient_tomato) 

什麼是最rails-api方式驗證結合在一起的sizeingredient應該是唯一的Component表?

我應該在Component的控制器中實現一些邏輯還是可以設置一些規則/範圍/無論什麼?

請原諒我的無知,我剛開始學習Ruby(和Rails)。我使用Rails 4.2.6Ruby 2.3.0p0 (2015-12-25 revision 53290)

在此先感謝。

回答

2

您將需要爲模型添加一個範圍唯一性驗證,併爲組件表添加一個唯一索引。

# app/models/component.rb 
class Component < ActiveRecord::Base 
    ... 
    validates :size_id, uniqueness: { scope: :ingredient_id } 
    ... 
end 

# app/db/migrate/20160412134948_add_uniqueness_index_to_components_table.rb 
class AddUniquenessIndexToComponentsTable 
    def change 
    add_index :components, [:size_id, :ingredient_id], unique: true, name: 'components_uniqueness_validation' 
    end 
end 

添加唯一索引的原因是爲了確保多線程服務器的唯一性。這裏是一篇文章,你可以閱讀更多關於線程安全唯一性驗證的Rails,http://www.kpheasey.com/2016/02/09/thread-safe-model-uniqueness-validations/

+0

感謝您的一個很好的提示。至少我對示波器有很好的感受。 :-)另外一個問題 - 我應該在模型的控制器中做些什麼來通知API用戶(嘗試使用POST方法添加這樣的重複信息),或者Rails(在上述範圍配置的幫助下)將返回有效的HTTP返回代碼(也可能是錯誤)本身? – tommus

+0

@tommus你不需要在控制器中做任何事情。模型驗證將會阻止記錄保存,並且您應該已經在視圖上顯示模型錯誤。看看這個導軌指南,http://guides.rubyonrails.org/active_record_validations.html – KPheasey

相關問題