2014-12-08 57 views
0

我想要一個模型,如果我對其進行更改並保存,它將保存爲新記錄。這就像不可變字符串的想法。我想知道是否有涵蓋這個領域的現有寶石/教程/最佳實踐?保存更改時克隆自我的不可變記錄

我看過的大多數寶石只是阻止你做任何修改。但是我想修改,只是將修改保存到記錄副本中。理論上這應該包括Rails中的任何更新方式,例如update_attributessave也應該返回記錄的新副本。

+0

你想在你的應用程序中有一種更新歷史記錄?如果是這樣看看paper_trail創業板,https://github.com/airblade/paper_trail – rmagnum2002 2014-12-08 09:06:24

+0

@ rmagnum2002沒有不是真的。我想使現有的關聯不受影響,這意味着我想保持現有記錄不受影響 – lulalala 2014-12-08 09:12:09

回答

0

所以最後我把以下內容加入到我的模型中。

爲了簡單起見,我通過只讀方式阻止對內置保存功能的訪問。

然後我有一個方法來保存修改。副本將被保存,但會更新對其的所選引用。例如,當我更新價格對象時,我還使用該價格更新現有產品以指向新的價格記錄。雖然訂單仍然會參考舊記錄。

def readonly? 
    persisted? 
    end 

    def save_as_clone 
     return self if ! changed? 

     copy = self.dup 
     ActiveRecord::Base.transaction do 
     copy.save! 
     if copy.persisted? 
      # Update existing references 
      self.products.update_all(price_id:copy.id) 
     end 
     end 
     copy 
    end 

    def destroy 
    # remove mapping only but do not destroy self 
    end 

    def delete 
    # remove mapping only but do not destroy self 
    end 

我想我可以通過重寫保存/保存!/ update_attributes方法方法是比較含蓄。然而,由於這不是正常的行爲,我選擇了明確的並在此停止。如果任何人有更通用的解決方案,請將其發佈。

0

您可能會利用rails changed?方法。一個例子基於User模型:

def update 
    @object = YourClass.find(params[:id]) 

    if @object.changed? 
    # Create new object 
    else 
    # Action if no change has been made 
    end 
end 

,該changed?方法將檢查如果模型的任何屬性已經改變的要指定你將使用一個確切的屬性object.attributename_changed?

[10] pry(main)> u = User.last 
    User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('User', 'AnonymousUser', 'DeletedUser') ORDER BY "users"."id" DESC LIMIT 1 
=> #<User id: 5, login: "Carson725", firstname: "Hillard", lastname: "VonRueden"> 
[11] pry(main)> u.lastname = 'Someother' 
=> "Sergiu" 
[12] pry(main)> u.changed? 
=> true 
[13] pry(main)> u.firstname_changed? 
=> false 
[14] pry(main)> u.lastname_changed? 
=> true 
[15] pry(main)> 

紅寶石2.1.5p273 /滑軌3.2.21

http://api.rubyonrails.org/classes/ActiveModel/Dirty.html

+0

謝謝,但如果解決方案在ActiveModel級別而不是控制器級別實現,則會更好。 – lulalala 2014-12-08 09:19:52

+0

同意,這將是.. :) Might做一些其他的SO用戶會分享一個更好的主意。想自己知道。 – rmagnum2002 2014-12-08 09:21:57

0

我還沒有聽說過具體的任務寶石,但在早些時候的Rails中只有只讀記錄,並且嘗試更新其中的例外情況。在現代版本的Rails中,這種類型的記錄已被棄用,並且沒有隻能爲關係設置的只讀屬性。但是你可以創建一個模型,將拒絕更新記錄,但在控制器,你可以捕捉特定的異常,並試圖創建一個基於拒絕一個新紀錄,就像如下:

class ReadonlyModelException < ActiveRecord::ActiveRecordError; end 

class ReadonlyModel < ActiveRecord::Base 
    before_update { |_| raise ReadonlyModelException } 
end 

class User < ReadonlyModel; end 

在控制器只是捕捉異常並改變行爲。

def update 
    user = User.where(id: params[:id]).first 
    user.update_attributes(name: "New name") # => ReadonlyModelException 
rescue ReadonlyModelException 
    redirect :create 
end 

注意:但在我的視野更好的辦法是不使用的特定對模型/控制器#update行動,只有#new/#create對。