Rails 3:如何更新has_one和has_many同时指向同一个表

时间:2011-07-12 01:26:00

标签: ruby-on-rails-3 activerecord

感谢您帮助淘汰了一个菜鸟。我在两个模型中有以下关系:

class Reader < ActiveRecord::Base
  has_many :books, :dependent => :destroy
  has_one :last_book, :class_name => "Book"
end

class Book < ActiveRecord::Base
  belongs_to :reader
end

我希望last_book成为与读者有关的最新书。

现在,在我的图书控制器中,我正在使用更新

中的类似代码创建如下书籍
def create
  @reader = Reader.find(params[:reader_id])
  @book = @reader.books.new (params[:book])
  @reader.last_data = @book
end

我认为这最终会两次写入数据库。有更干净/更有效的方法吗?

2 个答案:

答案 0 :(得分:3)

我认为你的协会真的不会像你想要的那样工作。您设置关联的方式,Reader模型将无法确定哪个图书是last_book,因为与特定阅读器关联的所有图书都具有相同的reader_id。使用reader.last_book = book将书籍分配给读者实际上只是将该书籍模型上的reader_id列设置为读者的ID。当你向reader.books添加一本书时也会发生同样的事情,所以这里确实没有任何区别因素来确定你在致电last_book时所指的那本书。 / p>

您可能最好只为您尝试建模的last_book关联定义方法。如果我理解您要正确执行的操作,last_book应该是最近为读者创建的书籍。在您的Reader模型中执行以下操作:

def last_book
  books.order('created_at desc').first
end

并删除此行

has_one :last_book, :class_name => "Book"

这应该允许您执行类似reader.last_book的操作,它将获取图书协会中最近创建的图书。这样,您就没有任何理由需要明确指定last_book,只需将图书添加到reader.books,当您需要上一本书时,只需致电reader.last_book

答案 1 :(得分:1)

has_one允许:order子句,因此您可以执行此操作:

class Reader < ActiveRecord::Base
  has_many :books, :dependent => :destroy
  has_one :last_book, :class_name => "Book", :order => "books.created_at desc"
end

然后在您的控制器操作中,您将删除其中一个作业

def create
  @reader = Reader.find(params[:reader_id])
  @book = @reader.books.new (params[:book])
end

杰夫史密斯的答案也是正确的。