Skip to content

Instantly share code, notes, and snippets.

@alpaca-tc
Created May 23, 2021 13:22
Show Gist options
  • Save alpaca-tc/174347329edec75e9e4d4f8bdd650834 to your computer and use it in GitHub Desktop.
Save alpaca-tc/174347329edec75e9e4d4f8bdd650834 to your computer and use it in GitHub Desktop.
関連の持ち主が同一人物であることをテスト
# 使い方
# validates_with(
# AssociationOwnerValidator,
# associations: {
# sub_item: :user
# },
# owner: -> { profile_image.user },
# if: %i[sub_item profile_image]
# )
class AssociationOwnerValidator < ActiveModel::Validator
def validate(record)
owner = owner_association(record)
return unless owner
options.fetch(:associations).each do |reflection_name, owner_reflection_name|
reflection = record.class.reflections[reflection_name.to_s]
owner_reflection = find_owner_reflection(record, reflection, owner_reflection_name)
if reflection.collection?
validate_collection(owner, record, reflection, owner_reflection)
else
validate_singlar(owner, record, reflection, owner_reflection)
end
end
end
private
def owner_association(record)
owner = options.fetch(:owner)
if owner.respond_to?(:call)
record.instance_exec(&owner)
elsif owner.respond_to?(:to_sym)
record.send(owner)
else
owner
end
end
def find_owner_reflection(record, reflection, owner_reflection_name)
if reflection.polymorphic?
record.association(reflection.name).klass.reflections[owner_reflection_name.to_s]
else
reflection.klass.reflections[owner_reflection_name.to_s]
end
end
def validate_singlar(owner, record, reflection, owner_reflection)
association = record.public_send(reflection.name)
record.errors.add(reflection.name.to_sym, :invalid_association) if invalid?(owner, association, owner_reflection)
end
def validate_collection(owner, record, reflection, owner_reflection)
record.public_send(reflection.name).each do |association|
record.errors.add(reflection.name.to_sym, :invalid_association) if invalid?(owner, association, owner_reflection)
end
end
def invalid?(owner, record, owner_reflection)
record.public_send(owner_reflection.name) != owner
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment