Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save hasaniskandar/4fa952b58b909b85fd08 to your computer and use it in GitHub Desktop.
Save hasaniskandar/4fa952b58b909b85fd08 to your computer and use it in GitHub Desktop.
Model concern that allows the HABTM records creation faster with single SQL's INSERT command
# Note:
# - Use fast_save_habtm_<singular>_ids for this feature
# - Callbacks and validations will NOT be triggered
# - Associations will be saved on after_save callback
# - Use <singular>_ids for normal habtm saving
module Shared::FastSaveHasAndBelongsToMany
extend ActiveSupport::Concern
included do
class_eval do
class << self
alias_method_chain :has_and_belongs_to_many, :fast_save_habtm
end
end
end
module ClassMethods
def has_and_belongs_to_many_with_fast_save_habtm(name, scope = nil, options = {}, &extension)
has_and_belongs_to_many_without_fast_save_habtm(name, scope, options, &extension)
define_fast_save_habtm_methods(name, options)
end
private
def define_fast_save_habtm_methods(name, options)
method_name = :"fast_save_habtm_#{name.to_s.singularize}_ids"
callback_name = :"fast_save_habtm_#{name}"
class_eval do
attr_accessor method_name
after_save callback_name, if: method_name
define_method callback_name do
send(name).delete_all
ids = send(method_name).select(&:present?)
if ids.present?
connection = self.class.connection
foreign_key = options[:foreign_key] || self.class.name.demodulize.underscore + "_id"
association_foreign_key = options[:association_foreign_key] || name.to_s.singularize + "_id"
join_table = options[:join_table] || [self.class.table_name, name.to_s].sort.join("_")
connection.execute "INSERT INTO #{connection.quote_table_name(join_table)} (#{connection.quote_column_name(foreign_key)}, #{connection.quote_column_name(association_foreign_key)}) VALUES " + ids.map { |n| "(#{id}, #{n.to_i})" }.join(", ")
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment