2015-04-08 72 views
0

我有一個地方模型has_many類別通過category_tags。 我對標籤進行了驗證,以確保它具有地點和類別,並避免在一個地方有兩次相同的類別。用has_many關係保存對象

型號:

class PlaceCategory < ActiveRecord::Base 

    has_many :place_category_tags, inverse_of: :place_category 
    has_many :places, through: :place_category_tags 

end 

class Place < ActiveRecord::Base 

    has_many :place_category_tags, inverse_of: :place 
    has_many :place_categories, through: :place_category_tags 

end 

class PlaceCategoryTag < ActiveRecord::Base 

    belongs_to :place 
    belongs_to :place_category 

    validates :place_id, presence: true 
    validates :place_category_id, presence: true, uniqueness: {scope: :place_id} 

end 

我也有一個指標我place_category_tags表,以確保在數據庫級別的唯一性:

add_index "place_category_tags", ["place_id", "place_category_id"], name: "index_place_category_tags_on_place_id_and_place_category_id", unique: true, using: :btree 

我的問題是,當我保存的標籤一個新的地方。驗證在保存位置之前在標籤上執行,因此它失敗,因爲place_id爲空。

2.1.5 :001 > place = Place.new() 
=> #<Place id: nil, name: "erg", created_at: nil, updated_at: nil> 
2.1.5 :002 > place.place_category_tags.build(place_category_id: 3) 
=> #<PlaceCategoryTag id: nil, place_id: nil, place_category_id: 3, created_at: nil, updated_at: nil> 
2.1.5 :003 > place.save 
    (0.3ms) BEGIN 
    (0.3ms) BEGIN 
    PlaceCategoryTag Exists (0.5ms) SELECT 1 AS one FROM "place_category_tags" WHERE ("place_category_tags"."place_category_id" = 3 AND "place_category_tags"."place_id" IS NULL) LIMIT 1 
    PlaceCategoryTag Exists (0.5ms) SELECT 1 AS one FROM "place_category_tags" WHERE ("place_category_tags"."place_category_id" = 3 AND "place_category_tags"."place_id" IS NULL) LIMIT 1 
    (0.2ms) ROLLBACK 
    (0.2ms) ROLLBACK 
=> false 
2.1.5 :004 > place.errors 
=> #<ActiveModel::Errors:0x0000000384e8a8 @base=#<Place id: nil, created_at: nil, updated_at: nil>, @messages={:"place_category_tags.place_id"=>["can't be blank"]}> 

我搜索了類似的問題,但我發現的是,我不得不添加我的地方的的has_many place_category_tags,這是我做的inverse_of選項,但它並沒有解決我的問題。

我也試圖在代替place_id和place_category_id地方,place_category執行驗證:

validates :place, presence: true 
validates :place_category, presence: true, uniqueness: {scope: :place} 

,似乎工作,但問題是,當我嘗試創建唯一性驗證不再執行兩個相同的place_category_tags,和我在數據庫級別的錯誤:

ActiveRecord::RecordNotUnique (PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_place_category_tags_on_place_id_and_place_category_id" 
DETAIL: Key (place_id, place_category_id)=(49, 3) already exists. 
: INSERT INTO "place_category_tags" ("created_at", "place_category_id", "place_id", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"): 
    app/controllers/backend/places_controller.rb:12:in `create' 

是否有人有什麼錯我的代碼的想法?

此外,我發現驗證在第二個例子中完全被跳過非常奇怪。如果有人有什麼事情的想法,那簡直太好了:)

編輯:我使用的Rails 4.1.8和Ruby 2.1.5p273

回答

0

如果您在控制檯寫,會發生什麼:

place = Place.new() 
place.place_category_tags.build(place_category_id: 3) 
place.place_category_tags.first.place 

如果inverse_of工作,它應該返回你的新地方。

在第一個示例中,它看起來像您的place_id是se nil。 在第二個示例中,它似乎是重複的有效數字。

如果您在索引遷移中刪除了unique: true標記,嘗試使用它也許更容易。

我認爲你應該對對象使用驗證而不是ID。

0

您可以使用validates_associated輔助方法進行驗證。

ActiveRecord在保存到數據庫之前驗證對象,因此您不必在數據庫端再次驗證它。

在你的情況下,它會檢查一個地方是否有效,然後驗證它的標籤。但是在創建標籤之前,您需要創建地點(要有ID),因此建議使用Place.create而不是Place.new,因爲Sharvy Ahmed

0

使用create而不是new將解決您的問題。這將確保在建立關聯對象之前,有一個id

place = Place.create 
place.place_category_tags.build(place_category_id: 3) 
place.save 
+0

是的,這工作,因爲這個地方已經創建並有一個ID,但對我來說,我呼籲在新的動作新,然後在我的控制器的創建acion創建的地方。標籤在表單中作爲嵌套屬性傳遞。 –