首页 > 解决方案 > 有没有办法更新次要属性?

问题描述

我目前正在开发一个 Ruby on Rails (v5.2) 项目,用于记录体育俱乐部的出席情况。每个学生都属于一个 payment_plan,每个 payment_plan 都有一个 classes_amount。Classes_amount 是学生在再次付款之前能够参加的课程数量。每个学生都有一个 classes_remaining 列来跟踪这一点。每次出勤后自动减少,每次付款后自动增加。

我想在更改学生的 payment_plan 时自动更新学生的 classes_remaining 属性。例如,如果学生想从 payment_plan A(5 个班级)更改为 payment_plan B(10 个班级),我希望他们的 classes_remaining 属性增加 10。当我将学生分配到新的付款计划时,他们的 classes_remaining价值保持为零。

这是我目前在我的更新方法中拥有的:

def update
    @student = current_club.students.find_by(id: params[:id])
    classes_amount = @student.payment_plan.classes_amount
    logger.debug "Classes amount is currently: #{classes_amount}"
    if classes_amount.present?
        if @student.classes_remaining.present?
            @student.classes_remaining = @student.classes_remaining + classes_amount
        else
            @student.classes_remaining = classes_amount
        end
    else
        @student.classes_remaining = nil
    end
    if @student.update_attributes(student_params)
        flash[:success] = "Student details updated"
        redirect_to @student
    else
        @activities = current_club.activities.all
        render 'edit'
    end
end

有一个 payment_plan 没有 classes_amount,因此这if classes_amount.present?条线。我的调试消息显示Classes amount is currently:

当学生的 payment_plan 发生变化时,如何自动更新学生的 classes_remaining 列?

标签: ruby-on-rails

解决方案


使用 ActiveModel::Dirty 可能最简单,https ://api.rubyonrails.org/classes/ActiveModel/Dirty.html

您只需将此行添加到您的学生模型中:

## app/models/student.rb

class Student << ApplicationBase
  include ActiveModel::Dirty
  ...
  ...
end

这使您可以访问以下方法:

student.payment_plan_id_changed?
student.payment_plan_id_changed?(from: 1, to: 2)

假设记录尚未保存,这些将返回 true 或 false。这意味着在您的模型中您现在可以执行以下操作:

## app/models/student.rb

class Student << ApplicationBase
  include ActiveModel::Dirty
  define_attribute_methods :payment_plan_id

  before_save :handle_payment_plan_changes!

  private

  def handle_payment_plan_changes!
    return unless payment_plan_id_changed?

    if payment_plan_id_changed?(from: 1, to: 2)
      classes_remaining += 5
    elsif payment_plan_id_changed?(from: 2, to: 1)
      classes_remaining -= 5
    end
  end
end

值得注意的是,每次保存学生时都会触发此 before_save,因此请确保您希望每次保存时都有此行为。如果这是一个问题,您始终可以handle_payment_plan_changes在保存之前从控制器手动调用(在将方法移出私有部分之后)。


推荐阅读