update_attributes,然后检查其中一个属性是否已更改

时间:2014-06-16 01:26:42

标签: ruby-on-rails ruby-on-rails-4

我有一个课程模型,用户可以使用表单进行编辑和更新。在控制器中,更新方法调用update_attributes(course_params),即强参数。这都是标准的,并且工作正常。

现在我试图找出更新期间特定属性是否正在发生变化。特别是,如果用户正在更改课程对象的points属性,我还需要将对象的points_recently_changed属性标记为true。快速而肮脏的实现将是这样的:

def update
  @course = Course.find(params[:id])
  @old_points = @course.points
  @course.update_attributes(course_params)
  @new_points = @course.points
  if @old_points != @new_points
    @course.points_recently_changed = true
    @course.save
  end
end

一种稍微不那么糟糕的做法可能是:

def update
  @course = Course.find(params[:id])
  @course.points_recently_changed = true if @course.points != params[:course][:points]
  @course.update_attributes(course_params)
end

然而,这些都不能满足我对干净,高效和易于阅读的实现的渴望。理想情况下,update_attributes可以选择返回在更新期间实际更改的属性数组。但它没有。

我看了ActiveModel::Dirty,但问题是它只能在保存之前运行。由于我使用了更新保存的update_attributes,因此has_changed?等方法在我的方案中不起作用。

任何建议将不胜感激。 :)

修改

这是管理员可以通过其更新课程对象的表单:

<%= form_for(@course) do |f| %>

  <%= f.label :title %>
  <%= f.text_field :title, required: true %>

  <%= f.label :course_logo %><br />
  <%= f.file_field :course_logo %>

  <%= f.label :description %>
  <%= f.text_field :description, required: true %>

  <%= f.label :worth, "Points" %>
  <%= f.number_field :worth %>

  <%= f.label :tag_ids, "Tags" %>
  <%= f.text_field :tag_ids, data: { load: @course.tags } %>

  <%= f.label :content %>
  <%= f.cktext_area(:content, rows: 10) %>

  <%= f.submit "Save changes", class: "btn btn-large btn-primary" %>

<% end %>

2 个答案:

答案 0 :(得分:1)

您可以使用after_validation回调来更新points_recently_changed属性。

#course.rb

after_validation :points_changed, if: ->(obj){ obj.points.present? and obj.points_changed? }

def points_changed
  self.points_recently_changed = true
end

说明:

考虑pointsCourse模型points_changed?方法中的属性,将根据点属性是否更新返回true或false。

一个例子

deep@IdeaPad:~/test/test_app$ rails c
2.1.1 :001 > course = Course.find(1)
=> #<Course id: 1, name: "Ruby on Rails", points: 2, points_recently_changed: true, created_at: "2014-06-16 01:51:48", updated_at: "2014-06-16 01:58:07"> 
2.1.1 :002 > course.changed? # will return true of false based on whether the course object has been updated or not
=> false 
2.1.1 :003 > course.points = "11"
=> "11"
2.1.1 :004 > course.points_changed?
=> true 
2.1.1 :005 > course.points_change
=> [2, 11] 

参考 - http://apidock.com/rails/ActiveRecord/Dirty

注意:在保存记录之前,必须使用changed?方法。保存记录后,调用changed?将返回false

答案 1 :(得分:0)

更快,而不是(太)丑陋的方法可能会重写update_attributes。这样您就可以在控制器中检查

if @courses.changes

课程控制器中的解决方案:

  def update_attributes(attributes)
    self.attributes = attributes
    changes = self.changes
    save
    self.changes = changes
  end