This seems like it should have a straightforward answer, but after much time on Google and SO I can't find it. It might be a case of missing the right keywords.
In my RoR application I have several models that share a specific kind of string attribute that has special validation and other functionality. The closest similar example I can think of is a string that represents a URL.
This leads to a lot of duplication in the models (and even more duplication in the unit tests), but I'm not sure how to make it more DRY.
I can think of several possible directions...
Number 3 seems the most reasonable, but I can't figure out how to extend ActiveRecord to handle anything other than the base data types. Any pointers?
Finally, if there is a way to do this, where in the folder hierarchy would you put the new class that is not a model?
Many thanks.
UPDATE:
One potential solution using Matt's mixin suggestion below (and using the URL example). Note, this is closer to psuedocode than real ruby and is intended to convey the principle rather than perfect syntax.
First, create a url
mixin:
module Url
def url_well_formed?
[...]
end
def url_live?
[...]
end
end
And in a Site
model, include this module:
Class Site < ActiveRecord:Base
include Url
validate :url_well_formed?
end
And when I need to check that the site at the URL is live, do...
if site.url_live?
[...]
end
The thing this doesn't solve is how to make the unit tests DRY. If I have another model, say Page
, that also uses the Url
mixin, it will still need a duplicate set of unit tests for the URL. Of course, I could put these in a helper, but that seems messy.
Is there a more fundamental solution, or is this as good as it gets?
Create an abstract model:
class CommonBase < ActiveRecord::Base
self.abstract_class = true # makes the model abstract
validate_format_of :url_field, :with => /.../
end
Inherit your models from the abstract model:
class User < CommonBase
end
class Post < CommonBase
end
You could create a module with all the common methods, and import the module? Google for mixins.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With