2

我有一个名为 ActiveRecord 的模型Books,它有一个has_one关联 onauthors和一个has_many关联 on publishers。所以下面的代码都很好

books.publishers

现在我有另一个 AR 模型,digital_publishers它很相似,但如果本书的作者回应,我想透明地使用它digital?- 让我用一些代码来解释

normal_book = Book.find(1)
normal_book.author.digital? #=> false
normal_book.publishers #=> [Publisher1, Publisher2, ...]

digital_book = Book.find(2)
digital_book.digital? #=> true
digital_book.publishers #=> I want to use the DigitalPublishers class here

因此,如果这本书的作者是数字的(作者是通过has_one :author关联设置的,所以它不像在 books 表上有一个带有 SQL 条件的 has_many 那样简单),我仍然希望能够调用.publishers它,但是让它返回一个的列表DigitalPublishers,所以我希望我的has_many关联有一些条件,首先检查这本书是否是数字的,如果是,则使用DigitalPublishers类而不是Publishers类。

我尝试使用after_find以下代码使用回调:

after_find :alias_digital_publisher

def alias_digital_publisher
  if self.author.digital?
    def publishers
      return self.digital_publishers
    end
  end
end

但这似乎没有奏效。另外,我使用的是 Rails 2.3。

4

3 回答 3

3

我需要有关该项目的更多信息才能真正提出建议,但这里有一些想法需要考虑:

1.出版商不应该属于书籍

我猜一个出版商可能与不止一本书有关,所以它们属于书籍并没有多大意义。我会考虑

#Book.rb
has_many :publishers, :through=>:publications

2. 将数字出版商存储在 publishers 表中

对列为 的数字发布者使用单表继承 (STI) typeDigitalPublisher或者仅添加一个布尔值,指示发布者是否为数字发布者。

这样,您只需调用book.publishers,您将获得可能是或可能不是数字的发布者,具体取决于分配的内容。

诀窍是您需要确保只有数字出版商被分配给数字作者的书籍。不过,这对我来说很有意义。

3.(或者)为发布者添加一个方法

def book_publishers
   author.digital? ? digital_publishers : publshers
end

我不是这个选项的真正粉丝,我认为你最好将所有出版商放在一张桌子上。

于 2012-10-10T20:35:29.213 回答
1

我的解决方案非常简单。

class Book < ActiveRecord::Base

    has_many :normal_publishers, :class_name => 'Publisher'
    has_many :digital_publishers, :class_name => 'DigitalPublisher'

    def publishers
        if self.digital?
            self.digital_publishers
        else
            self.normal_publishers
        end
    end

end

您仍然可以链接一些方法,例如book.publishers.count, book.publishers.find(...)

如果你需要book.publisher_ids,,,你可以定义这些方法,book.publisher_ids=如.book.publishers=book.publishers

上面的代码适用于 Rails 2.3.12。

更新:抱歉,我在发布此内容后注意到 klochner 的替代解决方案。

于 2012-10-12T14:21:18.977 回答
1

查看 Rails Guides v-2.3.11 中的这一部分。特别注意以下几点:

after_initialize 和 after_find 回调与其他回调有点不同。它们没有 before_* 对应物,注册它们的唯一方法是将它们定义为常规方法。如果您尝试使用宏样式类方法注册 after_initialize 或 after_find,它们将被忽略。

基本上,尝试将您定义after_find

def after_find
  ...
end

如果这不起作用,可能是因为书籍的字段尚未初始化,因此请尝试after_initialize

于 2012-10-09T16:48:01.363 回答