5

I have models User, Photo and Favorite, where favorites is a join table from users to photos, i.e.:

class User < ActiveRecord::Base
  has_many :favorites
  has_many :photos, through: `favorites`
end

class Photo < ActiveRecord::Base
  has_many :favorites
  has_many :users, through: `favorites`
end

class Favorite < ActiveRecord::Base
  belongs_to :user
  belongs_to :photo
end

Say that @user is an instance of User and photo_ids is an array of primary keys of Photos. What's the fastest and/or most succinct way to add all of those photos to @user.photos?

The best I can up with is:

@user.favorites.create( photo_ids.map { |id| {photo_id: id } } )

But this seems pretty verbose to me. Does Rails not have a better way of handling this?

Other questions talk about creating multiple has_many: through: associations through a nested form but I'm trying to do this in a JSON API so there are no forms involved.

GMA
  • 5,816
  • 6
  • 51
  • 80

2 Answers2

6

How about

@user.photos << Photo.find_all_by_id(photo_ids)
BroiSatse
  • 44,031
  • 8
  • 61
  • 86
  • Didn't realise you could use `<<` on an ActiveRecord association. Thanks! – GMA Jan 16 '14 at 09:49
  • Also note that object on the right is an array - it still works though. – BroiSatse Jan 16 '14 at 10:00
  • Actually I don't think this would work, wouldn't `Photo.find_by_id` only return one result? `Photo.where(id: photo_ids)` or `Photo.find(photo_ids)` both work fine though. – GMA Jan 16 '14 at 10:04
  • 4
    Cool. Worth noting that `find_by_*` and `find_all_by_*` syntax is deprecated in Rails 4. I used `where` but the effect is the same. – GMA Jan 16 '14 at 10:12
  • 2
    In rails 4 I would probably go for `find_all_by(id: photo_ids)` - it feels slightly better than `where` here but obviously there is no difference. :) Also note that Photo.find(photos_id) will raise an exception if it fails to find any of the records. – BroiSatse Jan 16 '14 at 10:13
  • Again, `find_all_by` is deprecated in Rails 4 and will not work. – phillyslick Aug 29 '15 at 01:09
0

You should be able to assign to the singular_collection_ids to replace the photos.

@user.photo_ids = photo_ids

If you want to "add" to the collection, you can use |=

@user.photo_ids |= photo_ids
eloyesp
  • 3,135
  • 1
  • 32
  • 47