【问题标题】:Is there a way to update a secondary attribute?有没有办法更新次要属性?
【发布时间】:2020-01-04 11:01:07
【问题描述】:

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

我想在更改学生的 payment_plan 时自动更新他们的 classes_remaining 属性。例如。如果学生想从 payment_plan A (5 classes) 更改为 payment_plan B (10 classes),我希望他们的 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


    【解决方案1】:

    使用 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(在将方法移出私有部分之后)。

    【讨论】:

    • 非常感谢,这个解决方案有效,但是我必须从模型中的define_attribute_methods :payment_plan_id 中删除:payment_plan_id,因为它抛出了错误数量的参数错误(预期为 1 为 0)。一旦我删除它就可以完美运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    • 2012-02-03
    • 2010-10-24
    相关资源
    最近更新 更多