Phone is defined as a string in db schema, but integers are stored as valid in Ruby
It seems to me that I am missing something very simple here ...
My db schema:
create_table "plans", force: true do |t|
t.string "phone1"
...
end
Here is a snippet from my console:
@plan = Plan.create(a bunch of params)
@plan.phone1 = "123"
@plan.valid?
# => true
# above is great, here where the problem comes in:
@plan.update_attribute("phone1", 123)
@plan.phone1
# => 123
@plan.valid?
# => true
This doesn't make my model tests very happy. And I'm not in this. From my model, here are all the relevant checks:
validates :phone1, presence: true
validates :phone1, length: { is: 3 }
source to share
ActiveRecord looks at yours schema.rb
and creates setters that are of type based on the column value.
class Plan < ActiveRecord::Base
# "Automagically" creating by Active Record.
# def phone1= val
# @phone1 = val.to_s
# end
end
So when you call .valid
in @plan
, the 'phone1' attribute is a string. I'm not sure what your test looks like, but if you do:
plan = Plan.new(123) expect(plan.valid?).to be_falsy
Expecting the plan to be invalid just because it passed a number different from yours just misunderstood how the rails work.
Given:
$ rails g model plan phone1:string ends:datetime
$ rails g migrate
irb(main):004:0>@plan = Plan.create(ends: Date.tomorrow, phone1: 123)
(0.3ms) begin transaction
SQL (1.2ms) INSERT INTO "plans" ("ends", "phone1", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["ends", "2015-06-24 00:00:00.000000"], ["phone1", "123"], ["created_at", "2015-06-23 02:21:39.236332"], ["updated_at", "2015-06-23 02:21:39.236332"]]
(1.2ms) commit transaction
=> #<Plan id: 2, phone1: "123", ends: "2015-06-24 00:00:00", created_at: "2015-06-23 02:21:39", updated_at: "2015-06-23 02:21:39">
irb(main):005:0> @plan.phone1 = 123456
=> 123456
irb(main):006:0> @plan.phone1.class
=> String
irb(main):007:0> @plan.update_attribute("phone1", 123)
(0.8ms) begin transaction
(0.3ms) commit transaction
=> true
irb(main):008:0> @plan.phone1.class
=> String
irb(main):013:0> @plan.ends = "2015-06-23"
=> "2015-06-23"
irb(main):014:0> @plan.ends
=> Tue, 23 Jun 2015 00:00:00 UTC +00:00
irb(main):015:0>
source to share
You can write your own check method to check that phone1
a String
*:
class Plan
validates :phone1, presence: true
validates :phone1, length: { is: 3 }
validates :special_validations
def special_validations
errors.add(:phone1, "Must be String") unless phone1.is_a? String
# add whatever you feel like
true
def
end
On the other hand, if you get a numeric field when loading data from a database, then the database field type is not a string. Maybe the older setting is kept?
* I'm not too smart as Rails functions have functions, so there might be a shortcut for that ...
source to share