Reputation: 4049
I feel like I'm missing something very simple here...
My db schema:
create_table "plans", force: true do |t|
t.string "phone1"
...
end
Here's a snippet from my console:
@plan = Plan.create(a bunch of params)
@plan.phone1 = "123"
@plan.valid?
# => true
# above is great, here's where the problem comes in:
@plan.update_attribute("phone1", 123)
@plan.phone1
# => 123
@plan.valid?
# => true
This is not making my model tests very happy. Nor me for that matter. From my model, here are all the relevant validations:
validates :phone1, presence: true
validates :phone1, length: { is: 3 }
Upvotes: 3
Views: 78
Reputation: 102134
ActiveRecord looks at your schema.rb
and creates setters which typecast 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
on @plan
the 'phone1' attribute is a string. I'm not sure what your test looks like but if your are doing:
plan = Plan.new(123)
expect(plan.valid?).to be_falsy
Expecting plan to be invalid solely because it's passed a number than your have simply misunderstood how rails works.
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>
Upvotes: 1
Reputation: 19221
You could write a custom validation method to check that phone1
is 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 numerical field when loading the data from the database, than your database's field type isn't a string. Maybe an older setting persists?
* I'm not too savvy as far as the Rails specialty features go, so there might be a shortcut to this...
Upvotes: 0