0

我有一個應用程序可以從可用於指定頁面佈局的小部件選擇中創建頁面(稱爲活動頁面)。我正在研究加載和編輯活動頁面內容的功能,更改內容並更新該頁面的相關條目。頁面上特定小部件的順序存儲在名爲page_display_order的列中。頁面顯示順序在整個活動頁面中是唯一的,因爲兩個小部件不能位於頁面上的相同位置。這是在更新頁面時有時會引發錯誤的列。更新嵌套屬性時,Rails作用域唯一性約束會引發錯誤

我爲屬於廣告系列網頁控件模型是這樣的:

class CampaignPagesWidget < ActiveRecord::Base 

    belongs_to :campaign_page, inverse_of: :campaign_pages_widgets 
    belongs_to :widget_type 
    has_one :actionkit_page 

    validates_presence_of :content, :page_display_order, :campaign_page_id, :widget_type_id 
    # validates that there are not two widgets with exactly same content on the same campaign page 
    # and that the page display order integer is unique across the widgets with that campaign page id 
    validates_uniqueness_of :page_display_order, :content, :scope => :campaign_page_id 
end 

這是怎樣的小部件數據從頁面請求時在編輯頁面(在campaign_pages_controller.rb)更新讀取。它首先找出它是哪種類型的小部件(存儲在小部件的表格和模型中),然後使用頁面編輯中指定的小部件的內容填充對象,並將其推送到指定嵌套屬性的數組中更新活動頁面時更新:

@campaign_page = CampaignPage.find params[:id] 
@widgets = @campaign_page.campaign_pages_widgets 

permitted_params = CampaignPageParameters.new(params).permit 
widget_attributes = [] 
params[:widgets].each do |widget_type_name, widget_data| 
     # widget type id is contained in a field called widget_type: 
     widget_type_id = widget_data.delete :widget_type 
     widget = @widgets.find_by(widget_type_id: widget_type_id) 
     widget_attributes.push({ 
     id: widget.id, 
     widget_type_id: widget_type_id, 
     content: widget_data, 
     page_display_order: i}) 
     i += 1 
    end 

    permitted_params[:campaign_pages_widgets_attributes] = widget_attributes 
    @campaign_page.update! permitted_params.to_hash 
    redirect_to @campaign_page 

在某些情況下這種更新和預期的重定向,在其他時候,它引發以下錯誤:

ActiveRecord::RecordInvalid in CampaignPagesController#update Validation failed: Campaign pages widgets page display order has already been taken, Campaign pages widgets is invalid

我是新來的Ruby和Rails和我將非常感謝關於我可能做錯的建議以及我應該如何做得更好。對於如何做Rails方式我沒有很好的訣竅,我知道我必須重構控制器中的代碼。

更新:僅當存在多個小部件時纔會引發該錯誤。事情工作正常,如果我註釋範圍的唯一性約束。它真正地更新現有的條目而不是創建新條目,所以這不成問題。

回答

0

發生這種情況是因爲小部件更新不會一次發生 - 它們一次只運行一個小部件。 Rails通過查詢數據庫查找具有相同數據的現有行來檢查唯一性,如果發現具有與您要保存的對象不同的ID,則會停止。例如,假設你有

| id | campaign_page_id | page_display_order | 
| 10 | 100    | 1     | 
| 20 | 100    | 2     | 

當您嘗試切換小部件秩序,[10, 2] [20, 1],Rails的開始控件節省10,去檢查它的新訂單(2)是獨一無二的。但是,它已經發現了這個命令的小部件20行,並引發了你所看到的錯誤。

退房acts as list,這是一個寶石,將爲您管理這個。否則,我認爲你需要繞過Rails並手動執行位置更新。

+0

謝謝您的解釋!這確實是問題所在。自從我更新小部件以來,我簡單地用'page_display_order:widget.page_display_order'替換了'page_display_order:i'。 –