简体   繁体   English

Rails - attr_accessor :- 读取属性值而不是覆盖它的函数

[英]Rails - attr_accessor :- read the attribute value instead of the function overriding it

I have a model Customer that accepts a virtual attribute opening_balance .我有一个接受虚拟属性opening_balance的模型Customer Code looks something like this:代码如下所示:

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

But the issue here is self.opening_balance is calling the method defined in the class not the value stored in attr_accessor's opening_balance attribute.但这里的问题是self.opening_balance调用的是类中定义的方法,而不是存储在 attr_accessor 的 opening_balance 属性中的值。

I tried one more solution:我尝试了另一种解决方案:

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

But this also doesn't work.但这也行不通。

How to read the value stored in the actual attribute?如何读取存储在实际属性中的值? Any help would be appreciated.任何帮助,将不胜感激。 I am using rails 5.1.我正在使用导轨 5.1。

Thanks!谢谢!

attr_accessor defines a instance variable and a method to access it (read/write). attr_accessor定义了一个实例变量和一个访问它的方法(读/写)。

So the easy way is to write:所以最简单的方法是写:

def open_ledger_account
  create_ledger_account!(opening_balance: @opening_balance)
end

The read_attribute would only work if opening_balance was an attribute in the database on Customer . read_attribute只有在opening_balanceCustomer数据库中的一个属性时才有效。

First you have to understand that attr_accessor does not define instance variables.首先你要明白attr_accessor没有定义实例变量。 It just creates setter and getter methods.它只是创建 setter 和 getter 方法。 What attr_accessor :name does is: attr_accessor :name作用是:

class Person
  def name
    @name
  end

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

Now you can access the instance variable from the outside:现在您可以从外部访问实例变量:

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

And you can also access the instance variable from the inside by using the getter method instead of @name :您还可以使用 getter 方法而不是@name从内部访问实例变量:

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

attr_accessor does not "define" a instance variable. attr_accessor不“定义”实例变量。 There is no declaration of members/attributes in Ruby like in for example Java. Ruby 中没有成员/属性的声明,例如在 Java 中。 An instance variables is declared when it is first set.实例变量在第一次设置时声明。 Accessing an instance variable that has not been assigned a value returns nil.访问尚未赋值的实例变量返回 nil。

So whats happing here:那么这里发生了什么:

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

Is that you are overwriting the getter created by attr_accessor .是你覆盖了attr_accessor创建的attr_accessor If you want to access the instance variable itself just use @opening_balance .如果您想访问实例变量本身,只需使用@opening_balance

However...然而...

You should just use delegate instead:您应该只使用委托

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM