开发者

Rails 3: how to update has_one and has_many pointing to the same table at the same time

开发者 https://www.devze.com 2023-03-19 07:45 出处:网络
Thanks for helping out a noob. I have the following relationships in two models: class Reader < ActiveRecord::Base

Thanks for helping out a noob. I have the following relationships in two models:

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

I want last_book to be the most recent book associated with reader.

Right now in my book controller I am creating book as follows with similar code in update

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

I think this ends up writing book twice to the database. Is there a cleaner/more efficient way to do this?


I don't think your associations will really work quite like you are intending them to. The way you have your associations set up, the Reader model won't be able to determine which book is the last_book, since all the books associated to a particular reader will have the same reader_id. Assigning a book to a reader with reader.last_book = book is really just setting the reader_id column on that book model to the reader's id. That's the same thing that will happen when you add a book to reader.books as well, so there really isn't any differentiating factor here for it to figure out which book you mean when you call last_book.

You'll probably be better off just defining a method for the last_book association you are trying to model. If I understand what you're trying to do correctly, last_book should be the most recently created book for a reader. In your Reader model do something like this:

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

and remove this line

has_one :last_book, :class_name => "Book"

That should allow you to do something like reader.last_book and it will grab the most recently created book in the books association. This way, you never have any reason to need to explicitly assign last_book, you just add the book to reader.books and when you need the last book just call reader.last_book.


has_one allows an :order clause, so you could do this:

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

Then in your controller action you would drop one of your assignments

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

Jeff Smith's answer is also correct.

0

精彩评论

暂无评论...
验证码 换一张
取 消