【问题标题】:Rails - attr_accessor :- read the attribute value instead of the function overriding itRails - attr_accessor :- 读取属性值而不是覆盖它的函数
【发布时间】:2019-11-26 08:28:06
【问题描述】:

我有一个模型Customer,它接受一个虚拟属性opening_balance。代码如下所示:

model Customer < ApplicationRecord
  attr_accessor :opening_balance

  has_one :ledger_account

  after_create :open_ledger_account

  def opening_balance
    ledger_account.opening_balance if ledger_account.present?
  end

  private

  def open_ledger_account
    create_ledger_account!(opening_balance: self.opening_balance)
  end

但这里的问题是self.opening_balance 调用的是类中定义的方法,而不是存储在 attr_accessor 的 opening_balance 属性中的值。

我尝试了另一种解决方案:

def open_ledger_account
  create_ledger_account!(opening_balance: self.read_attribute(:opening_balance))
end

但这也行不通。

如何读取存储在实际属性中的值?任何帮助,将不胜感激。我正在使用 Rails 5.1。

谢谢!

【问题讨论】:

  • opening_balance 属性在保存前可用。保存客户对象后,在回调中它只获取与新创建的客户对象关联的属性。我建议您使用嵌套表单来执行此操作,在自定义模型中您可以获得 opening_balance 作为嵌套属性。

标签: ruby-on-rails activerecord ruby-on-rails-5


【解决方案1】:

attr_accessor 定义了一个实例变量和一个访问它的方法(读/写)。

所以最简单的方法是写:

def open_ledger_account
  create_ledger_account!(opening_balance: @opening_balance)
end

read_attribute 仅在opening_balanceCustomer 上数据库中的一个属性时才有效。

【讨论】:

  • attribute_accessor 没有定义实例变量。它只是创建了一个 setter 和 getter 方法。每当您第一次为它们赋值时,实例变量都是“定义的”。所以调用 setter 方法会“定义”变量。
  • 显然正确,因为在 ruby​​ 中,没有其他方法可以“定义”实例变量,然后通过分配一个值。我的描述刻意简明扼要,以使答案简明扼要。
【解决方案2】:

首先你要明白attr_accessor 没有定义实例变量。它只是创建 setter 和 getter 方法。 attr_accessor :name 所做的是:

class Person
  def name
    @name
  end

  def name=(value)
    @name = value
  end
end

现在你可以从外部访问实例变量了:

p = Person.new
p.name = 'Jane'
puts p.name

你也可以使用getter方法而不是@name从内部访问实例变量:

class Person
  attr_accessor :name
  def hello
    "hello my name is: #{name}"
  end
end

attr_accessor 没有“定义”实例变量。 Ruby 中没有成员/属性的声明,例如 Java。实例变量在第一次设置时被声明。访问一个没有赋值的实例变量返回 nil。

那么这里发生了什么:

class Customer < ApplicationRecord
  attr_accessor :opening_balance
  # ...
  def opening_balance
    ledger_account.opening_balance if ledger_account.present?
  end
end

您是否正在覆盖attr_accessor 创建的getter。如果你想访问实例变量本身,只需使用@opening_balance

但是...

你应该改用delegate

class Customer < ApplicationRecord
  has_one :ledger_account
  delegate :opening_balance, to: :ledger_account
end

【讨论】:

  • 我喜欢代表的建议。我的猜测是attr_accessor 存在是因为在创建新客户时,可以立即以相同的形式输入期初余额。不幸的是,使用委托会破坏该解决方案;但恕我直言,这最终会导致更清洁的解决方案,让例如让控制器处理 1) 新客户的创建和 2) 分类帐帐户,而不是让模型处理它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-14
  • 2018-07-28
  • 1970-01-01
  • 2017-05-22
  • 1970-01-01
相关资源
最近更新 更多