Каков код по умолчанию для массового has_many :через назначение соединения в рельсах?
-
16-09-2019 - |
Вопрос
У меня есть базовое двунаправленное отношение has_many :through:
calendars have many calendar_calendar_events
calendars have many events through calendar_calendar_events
events have many calendar_calendar_events
events have many calendars through calendar_calendar_events
Я хочу назначить календари событию с базовыми calendar_ids=
функция, которая устанавливает has_many :through, однако я хочу переопределить эту функцию, чтобы добавить немного дополнительной магии.Я просмотрел исходный код рельсов и не смог найти код этой функции.Мне интересно, может ли кто-нибудь указать мне на это.Затем я переопределю его для этого класса, чтобы добавить то, что хочу :)
Решение
Исходный код вы можете найти в файле lib/active_record/associations.rb
в строке 1295
def collection_accessor_methods(reflection, association_proxy_class, writer = true)
collection_reader_method(reflection, association_proxy_class)
if writer
define_method("#{reflection.name}=") do |new_value|
# Loads proxy class instance (defined in collection_reader_method) if not already loaded
association = send(reflection.name)
association.replace(new_value)
association
end
define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
ids = (new_value || []).reject { |nid| nid.blank? }
send("#{reflection.name}=", reflection.class_name.constantize.find(ids))
end
end
end
Вам определенно следует избегать перезаписи этого метода для добавления волшебных вещей.Rails иногда уже «слишком много волшебства».Я бы предложил создать виртуальный атрибут со всей вашей собственной логикой по нескольким причинам:
- некоторые другие методы рельсов могут полагаться на реализацию по умолчанию
- вы полагаетесь на определенный API, который может измениться в будущих версиях ActiveRecord.
Другие советы
После недолгих поисков я нашел это:
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/collection_accessor_methods
Это выглядело не так, как я думал, поэтому я, вероятно, пропустил это.В итоге я переопределил метод Calendars= вместо метода Calendar_ids=, и все работает хорошо.
В ответ на ответ выше я использовал alias_method_chain, чтобы переопределить установщик по умолчанию и добавить свою функцию.Работает довольно хорошо, хотя я не уверен, почему мне нужно отправлять установщик метода вместо того, чтобы просто использовать его как обычно.Хотя, похоже, это не сработало, так что сойдет :)
def calendars_with_primary_calendar=(new_calendars)
new_calendars << calendar unless new_record?
send('calendars_without_primary_calendar=', new_calendars) # Not sure why we have to call it this way
end
alias_method_chain :calendars=, :primary_calendar