2012-03-31 34 views
2

我有HABTM型号ClientBookClient模型具有一个bookshelf_color属性来指示客户是否拥有一整套书籍,其中一部分是书籍,还是一部分书籍,或者没有任何书籍。一旦书架上的书籍发生变化,回调set_bookshelf_color应该反映这种变化。回调中的属性赋值不起作用?

问题是为什么我必须在"self."下面的私人回调中加上bookhelf_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

记住,你的模特属性是幕后只是实例变量 - 我们所做的,当我们与他们互动的调用由attr_accessor成立了getter和setter方法。当我们编写instance.bookshelf_color = "red"时,我们发送方法bookshelf_color=与参数"red"到接收器instance

很酷。当我们只写bookshelf_color = "red"会发生什么?

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

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,红宝石会知道我要送self的方法bar=,这将有理想的结果。

还有一些关于self的乐趣的进一步阅读,以及为什么你应该使用它,而不是Joe Yates' Blog

+0

谢谢,这解释了它 - 起初我看起来很奇怪。 – 2012-03-31 10:39:08