Reputation: 103
I have 2 models connected with has_many through association.
Book
can have many authors and Author
many books.
In AuthorsController
in update
action from API I get author's id and an array of books ids Parameters: {"books"=>"3,4,5", "id"=>"1"}
and I need to update author's books with them.
What is the best way to achieve that?
I tried author.books << Book.where(id: params[:books])
but the problem here is that if a book is already in author's books it will be duplicated.
Upvotes: 5
Views: 17243
Reputation: 461
The most efficient way is to use: has_many Association Reference. vide: Rails 4 Guides
4.3.1 Methods Added by has_many
When you declare a has_many association, the declaring class automatically gains 16 methods related to the association:
collection(force_reload = false)
collection<<(object, ...)
collection.delete(object, ...)
collection.destroy(object, ...)
collection=(objects)
collection_singular_ids
**collection_singular_ids=(ids)**
collection.clear
collection.empty?
collection.size
collection.find(...)
collection.where(...)
collection.exists?(...)
collection.build(attributes = {}, ...)
collection.create(attributes = {})
collection.create!(attributes = {})
Example:
Upvotes: 15
Reputation: 81
I know this might be too late, but you could also try
author.book_ids.push(params[:books]).flatten.uniq!
it'd be a little shorter and a single request.
Upvotes: 2
Reputation: 1428
If param[:books] is a string of numbers, you can convert it to an array with
"3,4,5".split(',').map {|x| x.to_i}
-> [3, 4, 5]
Then with Rails Collection methods, author.book_ids
should return an array that can be subtracted. So in all the feature would resemble:
author.books << Book.where(id: params[:books].split(',').map {|x| x.to_i} - author.book_ids)
Upvotes: -1
Reputation: 4322
author.books << Book.where(id: params[:books])
Performs unnecessary database queries.
You may need to remove the books that are already in the database
books_array = params[:books].split(',') - author.books.pluck(:id)
books_array.each do |a|
author.author_books.build(book_id: a)
end
# I assumed author_books is the join table
Upvotes: 3