Reputation: 2737
In my Rails 4 with Ruby 2 app I've the following model:
A Playlist
can have many Track
s and each Track
has its position
in its Playlist
. For each new Track
I want to set its position
to be the last, in thread-safe and/or multi-process-safe way.
In my research I found a bunch of projects that handle background jobs but I don't want this to be background, I want it to be synchronous. So the caller of my API will get the response with the correct position
.
The question is: what's the best way to make a synchronous serial queue that will be used to set the position of a Track
in its Playlist
?
Upvotes: 0
Views: 963
Reputation: 8574
If you want it to be synchronous, then you don't need a queue. Instead you'd just wrap a bit of code in a transaction where you find the last track position for that playlist, then set the position of the new track to be one more, then save the new track. Something like this (assuming you're in a controller action):
@playlist = Playlist.find params[:id]
@track = Track.new params[:track]
@playlist.transaction do
last_track = @playlist.tracks.order("posistion desc").first
@track.position = last_track.position + 1
@track.save
end
Upvotes: 1
Reputation: 21
As others suggested, if you want it to be a synchronous call just add it to your controller action. Just have one question, is there a requirement that you explicitly require a position attribute in the Track model. Because by default the track that you add to the playlist is added to the end
playlist = Playlist.find params[:id]
playlist.transaction.do
playlist.tracks.create(params[:track])
end
So when you want the last track that you added, then you can just fetch it by
playlist.tracks.last
If you want some kind of ordering for your tracks, then you can add some scope method to your Track model to render your tracks "by newest to oldest" or "by oldest to newest"(example without position attribute).
scope: sort_by_newest, order('created_at desc')
scope: sort_by_oldest, order('created_at asc')
If you still need an explicit tracking with the position attribute, then
playlist = Playlist.find params[:id]
track_params = params[:track] || {}
track_params.merge!({position: playlist.tracks.count('id') + 1})
playlist.transaction.do
playlist.tracks.create(track_params)
end
If you want some kind of ordering for your tracks, then you can add some scope method to your Track model to render your tracks "by newest to oldest" or "by oldest to newest"(example with position attribute).
scope: sort_by_newest, order('position desc')
scope: sort_by_oldest, order('position asc')
Hope it helps.
Upvotes: 1