I have two models Playlist
and Song
. The playlist has an ordered list of songs through a join table playlist_song_associations
with a position
attribute, e.g.
class Playlist < ApplicationRecord
has_many :playlist_song_associations, dependent: :destroy
has_many :songs, through: :playlist_song_associations
end
class Song < ApplicationRecord
has_many :playlist_song_associations, dependent: :destroy
has_many :playlists, through: :playlist_song_associations
end
class PlaylistSongAssociation < ApplicationRecord
belongs_to :playlist, touch: true
belongs_to :song
default_scope { order(position: :asc) }
end
Now I have an update controller method, where I do something like
playlist.songs = get_ordered_songs_from_params
And I want the associations to be ordered according to the order within the get_ordered_songs_from_params
array.
Is there a way to set this up, so that rails automagically sets the position
attribute on the associations?
2
Answers
The answer to whether or not you can get rails to do that automagically is maybe no, but maybe that’s not what you really want?
The way you have things set up, PlaylistSongAssociation is a real object. It exists like it has meaning. But it really kind of doesn’t have any meaning outside the context of the playlist. You never want to edit it alone.
A better model might be to have an array of song_ids in the Playlist and drop the PlaylistSongAssociation. The downside is that you almost certainly lose referential integrity to songs – but that might depend on your database of choice, and maybe that isn’t a real concern for you (if song deletion is unlikely or super rare or you’re fine recovering from it).
Add an array column in Rails
or using a json column. Again, depending on your database.
You can automatically fill the "position" field by using callbacks when creating PlaylistSongAssociation.
If you recently added the possibility of ordering your playlist and there was no "position" field before, you need to fill this field with data by using either migration or rake task. You can fill the field easily:
The idea here is to automate position setting when it gets added to playlist only once. If you will try to update position on the fly each time you call the playlist songs – you will ruin loading speed and will spam the db with requests. Always try to make only absolutely necessary amount of requests to preserve resources, cause every little thing counts.