回调中的属性赋值不起作用?

时间:2012-03-31 09:09:58

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

我有HABTM模型ClientBookClient模型有一个bookshelf_color属性,用于指示客户是否拥有完整的图书集,部分图书或其中没有图书。一旦书架上的书籍发生变化,回调set_bookshelf_color就会反映出这一变化。

问题是为什么我必须在下面的私人回调中使用"self."为bookshelf_color分配添加前缀以使其正常工作(否则不会)?

class Client < ActiveRecord::Base

  has_and_belongs_to_many :books, autosave: true, uniq: true,
    after_add: :set_bookshelf_color, after_remove: :set_bookshelf_color

  attr_accessible :id, :book_ids, :bookshelf_color

  private

    def set_bookshelf_color(book)
      if Book.pluck(:abbr).map{|b| books.map(&:abbr).map(&:to_s).include?(b.to_s)}.all?
        self.bookshelf_color = "green"
      elsif Book.pluck(:abbr).map{|b| books.map(&:abbr).map(&:to_s).include?(b.to_s)}.any?
        self.bookshelf_color = "yellow"
      else
        self.bookshelf_color = "red"
      end
    end
  # /private
end

1 个答案:

答案 0 :(得分:1)

请记住,您的模型属性只是幕后的实例变量 - 我们与它们交互时所做的就是调用attr_accessor设置的getter和setter方法。当我们写instance.bookshelf_color = "red"时,我们将带有参数bookshelf_color=的方法"red"发送给接收方instance

冷却。当我们只写bookshelf_color = "red"时会发生什么?

在Ruby中,裸字赋值用于定义局部变量。将name = "value"放在方法定义中将在本地范围内定义name,而不是在name=上调用self方法,即使该方法存在。

class Foo
  attr_accessor :bar

  def set_bar(val)
    bar = val
  end
end

f = Foo.new
f.set_bar "baz"
f.bar # still nil

如果我指定了一个明确的接收者self.bar = val,Ruby会知道我想发送self方法bar=,这会产生预期的结果。

对于self的乐趣有一些很好的进一步阅读,以及为什么要在Joe Yates' Blog上使用它。