When you need to cancel a Recurly subscription in Ruby, the Recurly gem provides a few options depending on whether you want an immediate cancellation or one at the end of the billing period.
Bulk Insert Records That Don’t Already Exist
A common pattern is inserting records in bulk, skipping any that already exist in the database. This avoids N+1 queries and is far more efficient than checking each record individually.
Using fast_inserter
The fast_inserter gem provides a clean way to batch-insert records efficiently:
# Get the IDs of the students
student_ids = Student.where(id: *params[:student_emplids]).pluck(:id)
# Get students that already have group assignments
student_with_group_ids = StudentGroup.where(student_id: *params[:student_emplids]).pluck(:student_id)
# Bulk insert only the ones that don't exist yet
StudentGroup.bulk_insert((student_ids - student_with_group_ids).map { |id|
{ student_id: id, group_id: @group.id }
})Using upsert with ActiveRecord
If you’re on Rails 6+, you can use upsert_all to insert records that don’t already exist:
# Prepare the records
students = Student.where(id: params[:student_emplids])
existing_ids = StudentGroup.where(student_id: params[:student_emplids]).pluck(:student_id)
records = students.where.not(id: existing_ids).map do |student|
{ student_id: student.id, group_id: @group.id, created_at: Time.current, updated_at: Time.current }
end
StudentGroup.upsert_all(records, unique_by: [:student_id, :group_id])Using Raw SQL with INSERT … ON CONFLICT
For PostgreSQL, you can use ON CONFLICT DO NOTHING to skip duplicates:
StudentGroup.connection.execute(<<~SQL)
INSERT INTO student_groups (student_id, group_id, created_at, updated_at)
SELECT id, #{@group.id}, NOW(), NOW()
FROM students
WHERE students.id IN (#{params[:student_emplids].join(',')})
ON CONFLICT (student_id, group_id) DO NOTHING
SQLExternal Resources
- Bulk insert records if they don’t exist in Rails on Stack Overflow
- fast_inserter gem on GitHub
- ActiveRecord
upsert_allin the Rails API docs