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.
精彩评论