Reputation: 4668
How do you restrict strings allowed in a string field to specific words?
Example: I have a model attribute animal:string
that I would like to exclusively accept ["dog", "cat", "bird", "fish"]
. Every thing else would make the object invalid.
Upvotes: 3
Views: 2204
Reputation: 118289
As I said, I'd go with Rails Enum feature.
class ModelName < ActiveRecord::Base
enum animals: %w(dog cat)
# ...
end
There is one gotcha which you might notice since this is called enum: you will need to update your database column to be an integer value. Rails will do implicit mapping between the integer value and the index of the value in the array automatically
If you go with Enum
feature, having the single line of code, Rails will generate several helper methods for you:
# Query method
model_name.dog?
model_name.cat?
#..
# Action method
model_name.cat!
model_name.dog!
#..
# List of statuses and their corresponding values in the database.
model_name.animals
Tried and Tested :
[arup@app]$ rails c
Loading development environment (Rails 4.1.1)
[1] pry(main)> Pet.create!(animals: 'cat')
(0.3ms) BEGIN
SQL (0.9ms) INSERT INTO "pets" ("animals", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["animals", 1], ["created_at", "2015-02-19 18:27:28.074640"], ["updated_at", "2015-02-19 18:27:28.074640"]]
(42.2ms) COMMIT
=> #<Pet id: 5, animals: 1, created_at: "2015-02-19 18:27:28", updated_at: "2015-02-19 18:27:28">
[2] pry(main)> Pet.create!(animals: 'cow')
ArgumentError: 'cow' is not a valid animals
from /home/arup/.rvm/gems/ruby-2.1.2@app/gems/activerecord-4.1.1/lib/active_record/enum.rb:103:in 'block (3 levels) in enum'
[3] pry(main)> Pet.animals
=> {"dog"=>0, "cat"=>1}
[5] pry(main)> Pet.first.dog?
Pet Load (0.8ms) SELECT "pets".* FROM "pets" ORDER BY "pets"."id" ASC LIMIT 1
=> false
[6] pry(main)> Pet.first.cat?
Pet Load (0.7ms) SELECT "pets".* FROM "pets" ORDER BY "pets"."id" ASC LIMIT 1
=> true
[7] pry(main)> Pet.first.cow?
Pet Load (0.7ms) SELECT "pets".* FROM "pets" ORDER BY "pets"."id" ASC LIMIT 1
NoMethodError: undefined method 'cow?' for #<Pet:0xbf8455c>
from /home/arup/.rvm/gems/ruby-2.1.2@app/gems/activemodel-4.1.1/lib/active_model/attribute_methods.rb:435:in `method_missing'
[8] pry(main)>
Pet.create!(animals: 'cow')
throws error, which confirmed that, Pet
model wouldn't accept anything other than the enum values.
Upvotes: 2
Reputation: 24347
Add an inclusion validation to your model:
validates :animal, inclusion: { in: %w(dog cat bird fish) }
Upvotes: 5
Reputation: 1013
you can use select field in your form, and write this in your model:
module Animal
dog = 1
cat = 2
bird = 3
fish = 4
end
and in tour form:
<%= f.select :animal, { "dog" => 1, "cat" => 2, "bird" => 3, "fish" => 4} %>
Upvotes: 0