【发布时间】:2014-08-24 05:21:27
【问题描述】:
我有一个名为 Document 的 ActiveRecord 模型,并围绕它实现了 CRUD 操作。我只是在验证失败时在请求之间保留Document 实例时遇到问题(因为发生这种情况时我想重定向到另一个页面)。
首先,我尝试将实例存储在闪存会话中:
# documents_controller.rb
def new
@document = flash[:document] || Document.new
end
def create
document = Document.new(document_params)
if document.save
return redirect_to documents_path
end
flash[:document] = document
redirect_to new_document_path
end
使用上面的代码,我希望实际的Document 实例存储在闪存会话中,但它变成了一个看起来有点像#<Document:0xad32368> 的字符串。在网上搜索了一会儿,发现由于某些原因,不能在会话中存储 ActiveRecord 对象。
有很多建议只是将对象的id 存储在闪存会话中,但我不能这样做,因为如您所见,对象尚未存储在数据库中。
接下来,我尝试在重定向后重构Document 实例,利用实例的attributes 方法(该方法返回可存储在会话中的可序列化哈希):
# documents_controller.rb
def new
@document = Document.new(flash[:document_hash] || {})
end
def create
...
flash[:document_attributes] = document.attributes
redirect_to new_document_path
end
这几乎解决了问题,除了没有保留验证错误(document.errors)的部分。此外,如果这用于持久化已存储在数据库中的实例(在更新 Document 实例时验证失败的情况下),我不确定原始属性和新属性之间的哪个会被持久化。
现在我已经想尽了办法。任何对此有一个体面的解决方案的人?
编辑:
您可能想知道为什么我仍然必须重定向到另一个页面,而不是只呈现新的文档视图模板或create 方法中的new 操作。我这样做是因为我的视图中有一些东西依赖于当前的控制器方法。例如,当您在文档创建页面上时,我有一个需要突出显示的选项卡(通过检查 action_name == "new" and controller_name == "documents" 来完成)。如果我这样做:
def create
...
render action: "new"
end
标签不会突出显示,因为 action_name 现在将是 create。如果action_name == "create",我也不能只添加附加条件来突出显示选项卡,因为也可以从索引页面(documents_path)创建文档。文档也可以从索引页面(documents_path)或详细页面(document_path(document))更新,如果update方法验证失败,我想重定向到上一页。
【问题讨论】:
-
我不是 100% 确定你为什么要这样做,但也许可以查看在请求之间缓存和存储数据的文档。请记住设置超时,这样您就不会遇到问题。 api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html
-
@Anti-Fun 根据 ActiveSupport Cache 文档,
ActiveSupport::Cache::Store can store any serializable Ruby object.。而 ActiveRecord 对象不能存储在会话中的原因是因为一些序列化问题。所以我猜(不确定,还没有尝试过)缓存 ActiveRecord 对象仍会将其存储为字符串? -
缓存封送对象(因此可以序列化几乎任何东西)而会话(从 4.1 开始)默认使用 json。
标签: ruby-on-rails session activerecord ruby-on-rails-4.1