保存前实施审核 - 控制器或型号?

时间:2011-01-28 17:59:09

标签: ruby-on-rails ruby

有没有办法对现有记录进行“保存”而不是使用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

2 个答案:

答案 0 :(得分:1)

您的复杂处理和验证应在模型内完成。脂肪控制器几乎总是比脂肪模型差。

为了说清楚,让我们举个例子。

假设您有一个模型Post。您在数据库中存储了titlecontent。并且假设您不希望使用直接输入这些字段,而是其他四个字段: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如何简化我的生活,帮助我编写好的,可维护的代码,并为我的客户的业务增加价值”

尝试强制您的业务需求符合示例中显示的代码或始终询问“最佳实践”是一个常见的错误。或者换句话说:询问您的框架可以为您做什么,而不是您可以为您的框架做些什么!

话虽这么说,你应该努力在模型中加入尽可能多的逻辑,并尝试简化控制器。这个话题已经被讨论过死亡 - 只是谷歌“胖模型瘦身控制器”的大量相关帖子。

请特别注意,您无需限制自己使用内置方法saveupdate_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是推出这些方法并帮助您满足特定要求的好方法。它还有助于实现关注点的良好分离,因为您最终会单独测试方法,这有助于编写可维护的代码。