有没有办法对现有记录进行“保存”而不是使用update_attributes?
我保存的一半值是根据用户输入计算的,因此不存在于params散列中。此外,可能有多个用户审核周期,这意味着:id从params哈希中删除(我将其保存在会话哈希中)。
对我来说,在@post的最终版本上“保存”似乎在概念上更简单。我最终将@post的最终版本保存在属性哈希中,然后返回数据库以获取原始记录,然后执行update_attributes。希望缓存第二次记录检索?实际上现在很容易在给定的编辑中生成一个更改列表,所以如果它有效,我可能会继续使用它,但它看起来很尴尬。
什么是“Rails方式?”我是新来的,想要适应。
<form is submitted>
@post = Post.new(params[:post])
<lots of calculations and validity checking>
finalattrhash = @post.attributes
@post = nil
@post = post.find(session[:postid])
respond_to do |format|
if @post.update_attributes(finalattrhash)
session[:postid] = nil
format.html { redirect_to(@post, :notice => 'post was successfully updated.') }
else ... end
end
答案 0 :(得分:1)
您的复杂处理和验证应在模型内完成。脂肪控制器几乎总是比脂肪模型差。
为了说清楚,让我们举个例子。
假设您有一个模型Post
。您在数据库中存储了title
和content
。并且假设您不希望使用直接输入这些字段,而是其他四个字段:trip_name,trip_date,visited和with_who。 (当然,这不是'真实案例':D)
class Post < ActiveRecord::Base
# DB fields: title:string, content:text
attr_accessor :trip_name, :trip_date, :visited, :with_who
attr_protected :title, :content # This line could be ignored, but to only protected these two fields from mass assignment.
before_save :complex_handles
validates :title, :presence => true, :uniqueness => true
validates :content, :presence => true
private
def complex_handles
@title = @trip_name + " " + @trip_date
@content = @visited + " " + @with_who
end
end
所以你的表单会给你以下哈希:
params[:post] = {
:trip_name => "some trip",
:trip_date => "2010-01-29",
:visited => "Hong Kong",
:with_who => "with my GF"
}
这应该是一个普通的简单形式,控制器也是最简单的形式:
respond_to do |format|
if @post.update_attributes(params[:post])
format.html { redirect_to(@post, :notice => 'post was successfully updated.') }
else
...
end
end
由于所有这些复杂的逻辑和验证都与模型本身相关,因此最好保留在模型中。通过这种方式,您的控制器和视图将非常干净。
=====更新=====
如果我的理解是正确的,我猜你有一个带有两个按钮的表单(一个是review
,一个是finalize
)。要查看,您只需更新字段,而无需保存到数据库。
因此,为两个提交按钮提供不同的name
属性会更容易。在您的控制器中:
respond_to do |format|
if (params[:action] == "finalize" && @post.update_attributes(params[:post]))
|| (params[:action] == "review" && @post.attributes = params[:post] && @post.valid?)
format.html { redirect_to(@post, :notice => 'post was successfully updated.') }
else
...
end
end
这部分看起来有点棘手。由于params [:action]可以一次成为一个值,因此您不会搞砸检查。
所以如果它是finalize,你只需调用update_attributes来保存它。否则,您可以在不保存的情况下分配这些属性,然后检查它是否有效。
但是,您必须稍微更新Post模型的代码:
# Before, I have used:
before_save :complex_handles
# Now, I change to:
before_validation :complex_handles
因此,在审核部分中调用@post.valid?
之前,请先进行处理。 (这不应影响最终部分)
答案 1 :(得分:1)
什么是“Rails方式?”我是新来的 在这附近,想要适应
不,它应该是相反的方式。问“Rails如何简化我的生活,帮助我编写好的,可维护的代码,并为我的客户的业务增加价值”
尝试强制您的业务需求符合示例中显示的代码或始终询问“最佳实践”是一个常见的错误。或者换句话说:询问您的框架可以为您做什么,而不是您可以为您的框架做些什么!
话虽这么说,你应该努力在模型中加入尽可能多的逻辑,并尝试简化控制器。这个话题已经被讨论过死亡 - 只是谷歌“胖模型瘦身控制器”的大量相关帖子。
请特别注意,您无需限制自己使用内置方法save
和update_attributes
。你已经宣布了两个行动:审查和完成。所以将这些添加到您的模型中:
class Post << AR::Base
def review
# do the validations, calculations, etc for the review step
end
def finalize
# do whatever you need for the finalize step
save # save the model instance
end
end
您也不必接受标准的RESTful操作名称。需要一个名为“审核”的行动?称之为:
resources :posts do
member do
post 'review' # maps to PostsController#review
end
end
BDD / TDD是推出这些方法并帮助您满足特定要求的好方法。它还有助于实现关注点的良好分离,因为您最终会单独测试方法,这有助于编写可维护的代码。