Working in a Rails app, I'm changing an optional belongs_to
association to be polymorphic. The existing code was validating the referential integrity of the association, and I'm trying to figure out how to translate that into the polymorphic idiom.
A simplified but illustrative example...
The old:
class Climb < ActiveRecord::Base
belongs_to :ladder
validate :ladder_exists_if_id_set
def ladder_exists_if_id_set
if ladder_id.present? && Ladder.find_by_id(ladder_id).blank?
errors.add('Ladder id', 'invalid. Set a different ladder id or nil.')
end
end
end
The new:
class Climb < ActiveRecord::Base
belongs_to :climbable, polymorphic: true
validate :climbable_exists_if_set
def climbable_exists_if_set
return unless climbable_id.present? && climbable_type.present?
klass = climbable_type.constantize
if klass.find_by_id(climbable_id).blank?
errors.add("#{klass} id", "invalid. Set a different #{klass} id or nil.")
end
end
end
This seems to work, but is it the right approach? It seems like I'm reimplementing the dynamic getter/setter methods that polymorphism gives you.
Sidenote : I'm able to ignore the case where only _type
or _id
is set because Rails invalidates the record in that case.
I am wondering, why were you validating uniqueness of id in this way in your old code on the first place? Isn't it easier to write validates :ladder_id, uniqueness: true, allow_nil: true [, allow_blank: true] (you should decide what you want to allow)
and with a custom message if you need one. Then see if Rails takes care of polymorphic association for you in your new code. I think you don't need your climbable_exists_if_set for that.
After your comment
It is probably even easier. You just have to validate presence of a ladder object. Note, not a ladder_id, but an object itself, so your validation should be as following:
validates :ladder, presence: true, allow_nil: true [, allow_blank: true]
In this case, rails validates that an actual ladder record with a given id exists in your ladders table.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.