I'd like to have a maximum number of associated records on a model. E.g. a project has_many tasks, but not more then twenty.
How can I enforce this rule?
The only solution that I've been able to come up with so far is an
INSERT INTO...SELECT query like this:
INSERT INTO
tasks (`id`,`project_id`,`title`,`body`)
SELECT
NULL, ?, ?, ?
FROM
tasks
HAVING
count(id) < MAX_NUMBER_OF_TASKS
LIMIT 1;
I'm currently using a custom method with ActiveRecord::Base.connection
and calling that instead of .create or .save when new_record? == true.
I haven't been able to try this, but I can't see why it shouldn't work.
Step one: Define a validator on the parent object (this is a simple implementation - could/should be made more generic):
class Project < ActiveRecord::Base
validate :max_tasks
def max_tasks
if tasks.count > 20
errors.add_to_base("Should not have more than 20 tasks")
end
end
end
Step two: Turn on validation of project from tasks:
class Task < ActiveRecord::Base
validates_associated :project
end
And I think you should be in business. When you try and save a new task, it'll validate the associated project, and the validation will fail if there are (now) more than 20 tasks associated.
Just in case you fancy making this more generic, you could do something like:
class NumberOfAssociatedValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if options[:maximum] && record.send(attribute).count > options[:maximum]
record.errors[attribute] << "must not have more than #{options[:maximum]}"
end
if options[:minimum] && record.send(attribute).count < options[:minimum]
record.errors[attribute] << "must not have less than #{options[:minimum]}"
end
end
end
class MyModel < ActiveRecord::Base
validates :my_association, :number_of_associated => {:maxiumum => 20}
end
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