Skip to content

Instantly share code, notes, and snippets.

@sudoremo
Last active June 26, 2024 08:45
Show Gist options
  • Save sudoremo/4204e399e547ff7e3afdd0d89a5aaf3e to your computer and use it in GitHub Desktop.
Save sudoremo/4204e399e547ff7e3afdd0d89a5aaf3e to your computer and use it in GitHub Desktop.
# This is a workaround for the rails issue described in
# https://github.com/rails/rails/issues/17368. If you use this,
# make sure you understand its code and what it does and what it
# doesn't.
#
# See below for an example.
# lib/lazy_ids.rb (i.e.)
module LazyIds
extend ActiveSupport::Concern
included do
after_save :persist_lazy_ids
end
def persist_lazy_ids
return unless @_lazy_ids
@_lazy_ids.each do |association, ids|
send(:"eager_#{association.to_s.singularize}_ids=", ids)
end
@_lazy_ids = {}
end
module ClassMethods
def lazy_ids(association)
alias_method :"eager_#{association.to_s.singularize}_ids=", :"#{association.to_s.singularize}_ids="
define_method "#{association.to_s.singularize}_ids=" do |ids|
@_lazy_ids ||= {}
@_lazy_ids[association] = ids
end
define_method association.to_s do
if @_lazy_ids && @_lazy_ids[association]
return self.class.reflect_on_association(association).klass.find(@_lazy_ids[association])
else
return super()
end
end
end
end
end
# Example:
class User
include LazyIds
has_many :groups_users
has_many :groups, through: :groups_users
lazy_ids :groups
end
u = User.first
u.group_ids = [1, 2, 3] # Aah, it does not save :)
u.save! # Now it does!
@sudoremo
Copy link
Author

Thanks! I needed to change line 37 from return super to return super() due to error "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly.". (Ruby 2.5.1, Rails 5.2.4.1).

Thank you, the gist is updated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment