MultiSelect Not Passing Multiple Values - join

I have a application that allows a user to upload a creative and assign it to multiple weeks
Week Model
class Week < ActiveRecord::Base
has_many :creative_weeks
has_many :creatives, :through => :creative_weeks
end
Creative Model
class Creative < ActiveRecord::Base
has_many :creative_weeks
has_many :weeks, :through => :creative_weeks
mount_uploader :image, CreativeUploader
end
Creative Weeks [Join Table]
class CreativeWeek < ActiveRecord::Base
belongs_to :week
belongs_to :creative
end
I know the association works which allows me to issue a creative to multiple weeks based on my console:
2.0.0p353 :020 > c = Creative.first
Creative Load (0.2ms) SELECT "creatives".* FROM "creatives" ORDER BY "creatives"."id" ASC LIMIT 1
=> #<Creative id: 10, name: "", account_id: 1, week_id: nil, campaign_id: 1, image: "Quakes_2013_DigiOOH_40YR_704x496.jpg", created_at: "2014-02-20 18:13:47", u
pdated_at: "2014-02-20 18:13:47">
2.0.0p353 :021 > c.week_ids
(0.2ms) SELECT "weeks".id FROM "weeks" INNER JOIN "creative_weeks" ON "weeks"."id" = "creative_weeks"."week_id" WHERE "creative_weeks"."creative_id" = ? [["
creative_id", 10]]
=> [3]
2.0.0p353 :022 > c.week_ids = [1, 2, 3]
Week Load (0.2ms) SELECT "weeks".* FROM "weeks" WHERE "weeks"."id" IN (1, 2, 3)
Week Load (0.1ms) SELECT "weeks".* FROM "weeks" INNER JOIN "creative_weeks" ON "weeks"."id" = "creative_weeks"."week_id" WHERE "creative_weeks"."creative_id"
= ? [["creative_id", 10]]
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "creative_weeks" ("created_at", "creative_id", "updated_at", "week_id") VALUES (?, ?, ?, ?) [["created_at", Thu, 20 Feb 2014 18:20:27
UTC +00:00], ["creative_id", 10], ["updated_at", Thu, 20 Feb 2014 18:20:27 UTC +00:00], ["week_id", 1]]
SQL (0.1ms) INSERT INTO "creative_weeks" ("created_at", "creative_id", "updated_at", "week_id") VALUES (?, ?, ?, ?) [["created_at", Thu, 20 Feb 2014 18:20:27
UTC +00:00], ["creative_id", 10], ["updated_at", Thu, 20 Feb 2014 18:20:27 UTC +00:00], ["week_id", 2]]
(1.0ms) commit transaction
=> [1, 2, 3]
2.0.0p353 :023 >
The issue I am having is getting this same functionality to work on the front end. It will only pass in one value, typically the last one chosen
In my form:
<div class="field">
<%= f.collection_select(:week_ids, Week.all, :id, :start_at, {}, multiple: true, name: 'creative[week_ids]') %>
</div>
Can anyone advise me what I am missing?
TIA

Change the select tag's name to this:
name: 'creative[week_ids][]'
That extra '[]' at the end of the name specifies that you want an array of values to be posted.
Using strong parameters you have to specify that the value will be an array:
def your_strong_params
params.require(:creative).permit(week_ids: [])
end

Related

Build vs Create in has many through relationship

I wonder if anyone can help me to understand about the difference between build and create in Has Many Through (HMT) relationship?
From my understanding after reading through stackoverflow and google, create is essentially build + save. However, it seems like create does more than just build + save. It also somehow save into the join table of the HMT relationship as shown below.
I created 3 models: user, wiki, and collaborator.
class User < ActiveRecord::Base
has_many :wikis, through: :collaborators
has_many :collaborators
end
class Wiki < ActiveRecord::Base
has_many :users, through: :collaborators
has_many :collaborators
end
class Collaborator < ActiveRecord::Base
belongs_to :user
belongs_to :wiki
end
Then I tested the build and create behavior in rails console:
$rails c
Loading development environment (Rails 4.0.10)
> user = User.first #create instance user
User Load SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> #<User id: 1, name: "Jayzz55">
> (user.wikis.build(title:"hello",body:"world")).save #build and save wiki
SQL INSERT INTO "wikis" ("body", "created_at", "title", "updated_at") VALUES(?,?,?,?) [["body","world"], ["ccreated_at, Sat, 08 Nov 2014 01:39:36 UTC +00:00], ["title","hello"], ["updated_at",Sat, 08 Nov 2014 01:39:36 UTC +00:00]]
=> true
>wiki1 = Wiki.first #create instance wiki called wiki1
=> #<Wiki id:1, title:"hello",body:"world">
>user.wikis
=> #<Wiki id:1, title:"hello",body:"world">
>user.wikis.count
=> 0
>wiki1.users
=> []
>Collaborator.all
=> []
> user.wikis.create(title:"second title",body:"another one")
begin transaction
SQL INSERT INTO "wikis" ("body", "created_at", "title", "updated_at") VALUES (?, ?, ?, ?)[0m [["body", "another one"], ["created_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00], ["title", "second title"], ["updated_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00]]
SQL INSERT INTO "collaborators" ("created_at", "updated_at", "user_id", "wiki_id") VALUES (?, ?, ?, ?) [["created_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00], ["updated_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00], ["user_id", 1], ["wiki_id", 2]]
=> #<Wiki id:2, title:"second title",body:"another one>
>user.wikis
=> [#<Wiki id: 1, title:"hello",body:"world">, #<Wiki id:2, title:"second title",body:"another one>]
>user.wikis.count
=> 1
>wiki2.users
=>#<User id: 1, name: "Jayzz55">
>Collaborator.all
Collaborator Load SELECT "collaborators".* FROM "collaborators"
=> #<Collaborator id:`, user_id:1, wiki_id: 2>
Case wiki1 : build and then save it
The data is not saved into the join table. calling user.wikis does return the object wiki, but running user.wikis.count return 0. Furthermore, running wiki1.users doesn't return the object user. Checking the join table Collaborator returns empty array.
Case wiki2 : create
The data is saved into the join table. calling user.wikis does return the object wiki. Running user.wikis.count return 1. Furthermore, running wiki1.users does return the object user. Checking the join table Collaborator, it does show the relationship clearly mapped.
Seems like Create is not simply just build + new. I'm curious about this behavior and hopefully someone can share their knowledge on this.
I believe that if you had in your first case instead written:
user.wikis.build(title:"hello",body:"world")
user.save
... you would find that ActiveRecord does the "full" save that create also does. The way you've written it, you're asking ActiveRecord to save the newly created Wiki instance, but not the association. So it doesn't create the record in the join table that's required.
Build + Save is equivalent to Create in any relationship

How to validate that payment can never cause invoice amount payable to be less than zero?

I have this class:
class Payment < ActiveRecord::Base
attr_accessible :amount, :invoice_id
belongs_to :invoice
validates :amount, :numericality => { :greater_than => 0, :less_than_or_equal_to => :maximum_amount }
after_save :update_amount_payable
after_destroy :update_amount_payable
private
def maximum_amount
invoice.amount_payable
end
def update_amount_payable
invoice.update_amount_payable
end
end
class Invoice < ActiveRecord::Base
has_many :payments
after_save :update_amount_payable
def update_amount_payable
update_column(:amount_payable_in_cents, new_amount_payable)
end
private
def new_amount_payable
(total - payments.map(&:amount).sum) * 100
end
end
The code above works. But how can I validate that no payment amount can ever cause invoice.amount_payable to be less than 0?
Especially when multiple payments for the same invoice are possible, this turns out to be tricky.
I've been trying to get my head around this for hours, but to no avail. Maybe an after callback to rollback the database can be used here?
Thanks for any help.
One cross-database solution that will work is to use optimistic locking. Essentially, it requires a special lock_version column, that is checked whenever an update is made. If the lock_version at the time an UPDATE is called is different than what the model is expecting, it throws an error noting that something outside of this model caused the record to change (thus invalidating the update). ActiveRecord supports this out of the box, and it will likely suffice for your needs if you don't mind blocking concurrent transactions altogether.
A case that it won't work is where you want to allow concurrent updates. In this case, you'll need to manually check the result during your update:
def update_amount_payable
new_value = new_amount_payable
raise "Payment amounts can't be greater than total invoice amount" if new_value < 0
count = Invoice.where(id: id, amount_payable_in_cents: amount_payable_in_cents).
update_all(amount_payable_in_cents: new_value)
raise ActiveRecord::StaleObjectError.new(self, 'update amount_payable_in_cents') if count != 1
end
private
def new_amount_payable
(total - payments.sum(:amount)) * 100 # get the amount sum from the database
end
I would change the field names. But given the current database schema try the following code:
app/models/invoice.rb
class Invoice < ActiveRecord::Base
has_many :payments
def still_open_amount
self.amount_payable_in_cents - self.payments.sum('amount_in_cents')
end
end
app/models/payment.rb
class Payment < ActiveRecord::Base
belongs_to :invoice
validates :amount_in_cents, :numericality => { :greater_than => 0 }
before_validation :check_all_payments
private
def check_all_payments
if self.new_record?
if (self.invoice.payments.sum('amount_in_cents') + self.amount_in_cents) > self.invoice.amount_payable_in_cents
errors.add(:amount, 'the invoice would be overpaid')
end
else
if (self.invoice.payments.sum('amount_in_cents') - self.amount_in_cents_was + self.amount_in_cents) > self.invoice.amount_payable_in_cents
errors.add(:amount, 'the invoice would be overpaid')
end
end
end
end
This will through a validation error if you try to create a overpaying payment:
~/Desktop/testapp ᐅ rails c
Loading development environment (Rails 4.0.0.beta1)
1.9.3-p286 :001 > i = Invoice.create(amount_payable_in_cents: 100)
(0.1ms) begin transaction
SQL (6.8ms) INSERT INTO "invoices" ("amount_payable_in_cents", "created_at", "updated_at") VALUES (?, ?, ?) [["amount_payable_in_cents", 100], ["created_at", Mon, 13 May 2013 19:23:24 UTC +00:00], ["updated_at", Mon, 13 May 2013 19:23:24 UTC +00:00]]
(0.8ms) commit transaction
=> #<Invoice id: 1, amount_payable_in_cents: 100, created_at: "2013-05-13 19:23:24", updated_at: "2013-05-13 19:23:24">
1.9.3-p286 :003 > p1 = i.payments.create(amount_in_cents: 90)
(0.1ms) begin transaction
Invoice Load (0.2ms) SELECT "invoices".* FROM "invoices" WHERE "invoices"."id" = ? ORDER BY "invoices"."id" ASC LIMIT 1 [["id", 1]]
(0.2ms) SELECT SUM("payments"."amount_in_cents") AS sum_id FROM "payments" WHERE "payments"."invoice_id" = ? [["invoice_id", 1]]
SQL (0.4ms) INSERT INTO "payments" ("amount_in_cents", "created_at", "invoice_id", "updated_at") VALUES (?, ?, ?, ?) [["amount_in_cents", 90], ["created_at", Mon, 13 May 2013 19:24:10 UTC +00:00], ["invoice_id", 1], ["updated_at", Mon, 13 May 2013 19:24:10 UTC +00:00]]
(1.0ms) commit transaction
=> #<Payment id: 1, invoice_id: 1, amount_in_cents: 90, created_at: "2013-05-13 19:24:10", updated_at: "2013-05-13 19:24:10">
1.9.3-p286 :004 > p2 = i.payments.create(amount_in_cents: 20)
(0.1ms) begin transaction
Invoice Load (0.2ms) SELECT "invoices".* FROM "invoices" WHERE "invoices"."id" = ? ORDER BY "invoices"."id" ASC LIMIT 1 [["id", 1]]
(0.1ms) SELECT SUM("payments"."amount_in_cents") AS sum_id FROM "payments" WHERE "payments"."invoice_id" = ? [["invoice_id", 1]]
(0.1ms) commit transaction
=> #<Payment id: nil, invoice_id: 1, amount_in_cents: 20, created_at: nil, updated_at: nil>
1.9.3-p286 :005 > p2.errors
=> #<ActiveModel::Errors:0x007fd57b8e36d8 #base=#<Payment id: nil, invoice_id: 1, amount_in_cents: 20, created_at: nil, updated_at: nil>, #messages={:amount=>["the invoice would be overpaid"]}>
1.9.3-p286 :006 >

Rails Engines - is it possible to add associations to the model in a container model like Forem does

This Question is more than a single question so breaking it up into more managable pieces: Rails Engines - simple possible engine to (1) add a model and (2) add the association in the containing class
I am testing out building a Rails engine and am curious whether I can add an association to a specific model in the hosting / container app.
The hosting app has a user model class (yes, this will never chnage) and my engine is called abc and I have a model in my engine called posts (so Abc::Post and the table is abc_posts). I'd like to add to the User class in the main app this association. As a drop dead simple try, I created in my engine:
#located in the engine at: abc/app/models/user.rb
class User < ActiveRecord::Base
has_many :abc_posts
end
the post file:
#located in the engine at: abc/app/models/abc/post.rb
module Abc
class Post < ActiveRecord::Base
attr_accessible :body, :header, :user_id
belongs_to :user
end
end
Via rails console, I was able to create records in the table (easy part) but the User class doesn't know about the association. Any ideas on how to get this done?
thx in advance
edit 1
I've tried using the decorators gem as used in forem (see comment below) and have this file:
#abc/app/decorators/lib/abc/user_class_decorator.rb
Object.const_get(User).class_eval do
has_many :abc_posts, :class_name => "Abc::Post", :foreign_key => "user_id"
end
I have included the decorators via:
lib/abc.rb
require "decorators"
but his doesn't seem to be working. Not sure if this is right strategy or whether syntax is even correct.
That should do the job - specify the class for the relationship:
class User < ActiveRecord::Base
has_many :posts, :class_name => "Abc::Post"
end
Hmmm, I created an example and it does work ...
class Parent < ActiveRecord::Base
has_many :children, :class_name => "Abc::Child"
end
The module with the class Child is in the model/abc.
module Abc
class Child < ActiveRecord::Base
belongs_to :parent
end
end
Here the journal
1.9.3-p194 :001 > Parent.create(:name => 'Mr Daddy')
(0.1ms) begin transaction
SQL (9.4ms) INSERT INTO "parents" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", Fri, 03 May 2013 10:49:54 UTC +00:00], ["name", "Mr Daddy"], ["updated_at", Fri, 03 May 2013 10:49:54 UTC +00:00]]
(1.9ms) commit transaction
=> #<Parent id: 1, name: "Mr Daddy", created_at: "2013-05-03 10:49:54", updated_at: "2013-05-03 10:49:54">
1.9.3-p194 :002 > Abc::Child.create(:name => 'Sammy boy', :parent => Parent.first )
Parent Load (0.3ms) SELECT "parents".* FROM "parents" ORDER BY "parents"."id" ASC LIMIT 1
(0.1ms) begin transaction
SQL (117.3ms) INSERT INTO "children" ("created_at", "name", "parent_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 03 May 2013 10:49:58 UTC +00:00], ["name", "Sammy boy"], ["parent_id", 1], ["updated_at", Fri, 03 May 2013 10:49:58 UTC +00:00]]
(2.1ms) commit transaction
=> #<Abc::Child id: 1, name: "Sammy boy", parent_id: 1, created_at: "2013-05-03 10:49:58", updated_at: "2013-05-03 10:49:58">
1.9.3-p194 :003 > Abc::Child.create(:name => 'Milly girl', :parent => Parent.first )
Parent Load (0.3ms) SELECT "parents".* FROM "parents" ORDER BY "parents"."id" ASC LIMIT 1
(0.2ms) begin transaction
SQL (0.8ms) INSERT INTO "children" ("created_at", "name", "parent_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 03 May 2013 10:50:15 UTC +00:00], ["name", "Milly girl"], ["parent_id", 1], ["updated_at", Fri, 03 May 2013 10:50:15 UTC +00:00]]
(2.7ms) commit transaction
=> #<Abc::Child id: 2, name: "Milly girl", parent_id: 1, created_at: "2013-05-03 10:50:15", updated_at: "2013-05-03 10:50:15">
1.9.3-p194 :004 > Parent.first.children.first
Parent Load (0.4ms) SELECT "parents".* FROM "parents" ORDER BY "parents"."id" ASC LIMIT 1
Abc::Child Load (0.3ms) SELECT "children".* FROM "children" WHERE "children"."parent_id" = ? ORDER BY "children"."id" ASC LIMIT 1 [["parent_id", 1]]
=> #<Abc::Child id: 1, name: "Sammy boy", parent_id: 1, created_at: "2013-05-03 10:49:58", updated_at: "2013-05-03 10:49:58">
1.9.3-p194 :005 > Parent.first.children.last
Parent Load (0.5ms) SELECT "parents".* FROM "parents" ORDER BY "parents"."id" ASC LIMIT 1
Abc::Child Load (0.4ms) SELECT "children".* FROM "children" WHERE "children"."parent_id" = ? ORDER BY "children"."id" DESC LIMIT 1 [["parent_id", 1]]
=> #<Abc::Child id: 2, name: "Milly girl", parent_id: 1, created_at: "2013-05-03 10:50:15", updated_at: "2013-05-03 10:50:15">
1.9.3-p194 :006 > Parent.first.children.count
Parent Load (0.3ms) SELECT "parents".* FROM "parents" ORDER BY "parents"."id" ASC LIMIT 1
(0.3ms) SELECT COUNT(*) FROM "children" WHERE "children"."parent_id" = ? [["parent_id", 1]]
=> 2

Adding JOIN for associated tables [duplicate]

This question already has an answer here:
Adding a JOIN between two tables
(1 answer)
Closed 9 years ago.
My Organization class looks something like this:
has_many Students
My Student class looks like this:
has_many Klasses
belongs_to Organization
My Klass class looks like this:
some field named : price
scope :top_expensive_classes, joins(:students).order('price DESC')
belongs_to Student
And my query looks like this:
#results = Klass.top_expensive_classes.where(organization_id: params[:id]).limit(RESULT_SET_COUNT)
Notice that it starts with Klass, so that's the problem because I am searching in the where class for organization_id but that is not in the Klass, it is in Student class , so somehow I should introduce a join somewhere to fix this but couldn't figure it out.
I think the real issue is your associations are likely incorrect.
A student has many classes
A class has many students
but what you have is
A student has many classes
A class belongs to a single student
This doesn't really make sense (at least in any situation I've ever seen a class and student interact). You should be creating a many-to-many relationship instead of a one-to-many relationship between Klass and Student.
class Student < ActiveRecord::Base
has_many :klasses, through: :student_klasses
has_many :student_klasses
end
class Klass < ActiveRecord::Base
has_many :students, through: :student_klasses
has_many :student_klasses
end
class StudentKlass < ActiveRecord::Base
belongs_to :student
belongs_to :klass
end
Once you have these correct associations in place, you need to call .joins on the :students association from the Klass class. You can do without the scope.
Klass.joins(:students).where("students.organization_id = ?", params[:id]).order('price DESC').limit(RESULT_SET_COUNT)
Read the guide on ActiveRecord Querying.
Here is the proof (using the exact model definitions above) that the ordering of the associations does not matter.
irb(main):001:0> s = Student.create(name: "Deefour")
SQL (3.6ms) INSERT INTO "students" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:33:32 UTC +00:00], ["name", "Deefour"], ["updated_at", Fri, 08 Mar 2013 01:33:32 UTC +00:00]]
=> #<Student id: 1, name: "Deefour", created_at: "2013-03-08 01:33:32", updated_at: "2013-03-08 01:33:32">
irb(main):002:0> kk = []
=> []
irb(main):003:0> kk << Klass.create(title: "Klass 1")
SQL (0.3ms) INSERT INTO "klasses" ("created_at", "title", "updated_at") VALUES (?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:06 UTC +00:00], ["title", "Klass 1"], ["updated_at", Fri, 08 Mar 2013 01:34:06 UTC +00:00]]
=> [#<Klass id: 1, title: "Klass 1", created_at: "2013-03-08 01:34:06", updated_at: "2013-03-08 01:34:06">]
irb(main):004:0> kk << Klass.create(title: "Klass 2")
SQL (0.3ms) INSERT INTO "klasses" ("created_at", "title", "updated_at") VALUES (?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:14 UTC +00:00], ["title", "Klass 2"], ["updated_at", Fri, 08 Mar 2013 01:34:14 UTC +00:00]]
=> [#<Klass id: 1, title: "Klass 1", created_at: "2013-03-08 01:34:06", updated_at: "2013-03-08 01:34:06">, #<Klass id: 2, title: "Klass 2", created_at: "2013-03-08 01:34:14", updated_at: "2013-03-08 01:34:14">]
irb(main):005:0> s.klasses = kk
Klass Load (0.1ms) SELECT "klasses".* FROM "klasses" INNER JOIN "student_klasses" ON "klasses"."id" = "student_klasses"."klass_id" WHERE "student_klasses"."student_id" = ? [["student_id", 1]]
SQL (0.4ms) INSERT INTO "student_klasses" ("created_at", "klass_id", "student_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00], ["klass_id", 1], ["student_id", 1], ["updated_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00]]
SQL (0.1ms) INSERT INTO "student_klasses" ("created_at", "klass_id", "student_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00], ["klass_id", 2], ["student_id", 1], ["updated_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00]]
=> [#<Klass id: 1, title: "Klass 1", created_at: "2013-03-08 01:34:06", updated_at: "2013-03-08 01:34:06">, #<Klass id: 2, title: "Klass 2", created_at: "2013-03-08 01:34:14", updated_at: "2013-03-08 01:34:14">]
irb(main):006:0> Student.first.klasses.map(&:id)
Student Load (0.2ms) SELECT "students".* FROM "students" ORDER BY "students"."id" ASC LIMIT 1
Klass Load (0.1ms) SELECT "klasses".* FROM "klasses" INNER JOIN "student_klasses" ON "klasses"."id" = "student_klasses"."klass_id" WHERE "student_klasses"."student_id" = ? [["student_id", 1]]
=> [1, 2]

Strange ActiveRecord model behavior

I have model
class Owner < ActiveRecord::Base
attr_accessible :telephone
validates_uniqueness_of :telephone
validates_telephone_number_of :telephone
before_validation :telephone_normalize
end
in rails console
a = Owner.new(:telephone => '949123456')
=> #<Owner id: nil, telephone: "949123456", created_at: nil, updated_at: nil>
1.9.3-p362 :002 > a.valid?
Owner Exists (0.1ms) SELECT 1 AS one FROM "owners" WHERE "owners"."telephone" = '+421949123456' LIMIT 1
=> false
1.9.3-p362 :003 > a
=> #<Owner id: nil, telephone: "421949123456", created_at: nil, updated_at: nil>
The same, when I save unique number:
1.9.3-p362 :006 > a.telephone = '949123457'
=> "949123457"
1.9.3-p362 :007 > a.save
(0.1ms) begin transaction
Owner Exists (0.2ms) SELECT 1 AS one FROM "owners" WHERE "owners"."telephone" = '+421949123457' LIMIT 1
SQL (2.3ms) INSERT INTO "owners" ("created_at", "telephone", "updated_at") VALUES (?, ?, ?) [["created_at", Wed, 16 Jan 2013 11:55:44 UTC +00:00], ["telephone", "421949123457"], ["updated_at", Wed, 16 Jan 2013 11:55:44 UTC +00:00]]
(88.3ms) commit transaction
=> true
Rails (3.2.11) omits '+' in the beginning of number. Type of number is string. It also saves it without plus sign (if it is unique), but when validating, it calls with plus sign.
What am I doing wrong?
It think telephone column in database is integer type. So the string you have passed is out of its range. That's why you have face this problem.
Unfortunetaly there was bug in my validates_telephone_number_of validator. It had modified attribute :-/
Say
> a = 'aaa' # => 'aaa'
> b = a.to_s # => 'aaa'
> b << 'c' # => 'aaac'
> b # => 'aaac'
> a # => 'aaac'
It is needed to use b = a.to_s.dup.

Resources