Reputation: 44066
Ok i have a model named Tire and I cant update the name field on some reserved names
class Tire < ActiveRecord::Base
RESERVED_TIRES = ['Michelin', 'Good Year', 'Firestone']
before_update :reserved_tires
def reserved_tires
if RESERVED_TIRES.include?(self.name)
self.errors.add(:base, "Cant be changed")
false
end
end
end
And i need to not allow the user to update any field is the current name is in the reserved words...this works for all fields other then when the user updates name.
For example is the user updates to "Michelinnnn" then it allows the update because self.name is "Michelinnnn" rather then 'Michelin' which is saved in the DB. Any ideas on how to address this
Upvotes: 0
Views: 90
Reputation: 2331
So the problem is strings that are similar, but not identical, to the reserved names? The "michelinnnn" example would be caught by using regular expressions instead of exact string matches:
RESERVED_TIRES = [/michelin/i, /good\s*year/i, /firestone/i]
...
if RESERVED_TIRES.find{|r| self.name =~ r}
The built-in Rails function is validates_exclusion_of, but I don't know if that can handle (arrays of) regular expressions.
However, that will only catch certain types of similar names. There are more general ways to calculate string similarity, but there is no watertight solution for this kind of problem.
Upvotes: 1
Reputation: 3859
If you mean you don't want to allow any change if the name before the change was reserved, then you can access the old name as name_was
.
Upvotes: 3
Reputation: 6444
THis should do the trick:
name_allowed = RESERVED_TIRES.inject(true) { |is_allowed, tire_name|
is_allowed &&= !self.name.include?(tire_name)
}
unless name_allowed
# add error
end
Upvotes: 1
Reputation: 434685
First of all, you probably want to use a validation instead of your before_update
:
class Tire < ActiveRecord::Base
RESERVED_TIRES = ['Michelin', 'Good Year', 'Firestone']
validate :reserved_tires, :unless => :new_record?
private
def reserved_tires
if RESERVED_TIRES.include?(self.name)
self.errors.add(:base, "Cant be changed")
end
end
end
The :unless => :new_record?
skips the validation for new records so you will be able to create them but changes will be prevented.
Then add another validation to catch them trying to change the name:
validate :cant_change_reserved_name, :if => :name_changed?
#...
def cant_change_reserved_name
if RESERVED_TIRES.include?(self.name_was)
self.errors.add(:name, "You cannot change a reserved name.")
end
end
Upvotes: 1