softcode
softcode

Reputation: 4668

Allow Only Specific Words for Attribute

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

Answers (3)

Arup Rakshit
Arup Rakshit

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

infused
infused

Reputation: 24347

Add an inclusion validation to your model:

validates :animal, inclusion: { in: %w(dog cat bird fish) }

Upvotes: 5

Zakaria
Zakaria

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

Related Questions