我想要一个模型,如果我对其进行更改并保存,它将被保存为新记录。这就像不可变字符串的想法。我想知道是否有现有的宝石/教程/最佳实践涵盖这个领域?
我看过的大多数宝石只是阻止你做任何修改。但是我想修改,只是将修改保存到记录的副本中。从理论上讲,这应该涵盖Rails中的任何更新方式,例如update_attributes
,而save
也应该返回新的记录副本。
答案 0 :(得分: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)>
ruby 2.1.5p273 / Rails 3.2.21
答案 1 :(得分:0)
我还没有听说过具体的任务宝石,但在早期的Rails中只有readonly记录,并且更新的尝试被异常更新。在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
对。
答案 2 :(得分: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
我想我可以通过覆盖save / save!/ update_attributes方法使其更加隐含。然而,由于这不是正常的行为,我选择明确并停在这里。如果有人有更一般的解决方案,请发布。