has_many/belongs_to 関係を介して関連付けられた Trainer モデルと Client モデルを作成しました。Trainer has_many Clients と Client belongs_to Trainer。ただし、 を使用して既存のクライアントを既存のトレーナーに追加しようとするTrainer.Clients << Client
と、データベースに保存されません。
クライアント モデル:
class Client < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation, :trainer_id
has_secure_password
belongs_to :trainer
validates :name, presence: true, length: { maximum: 40 }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true, length: { minimum: 6 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
before_save { |client| client.email = email.downcase }
end
トレーナー モデル:
class Trainer < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
has_many :clients
validates :name, presence: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true, length: { minimum: 6 }
before_save { |trainer| trainer.email = email.downcase }
end
データベースの Client テーブルには、trainer_id のforeign_id があります。
create_table "clients", :force => true do |t|
t.string "name"
t.string "email"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "password_digest"
t.integer "trainer_id"
end
コンソールでクライアント レコードをトレーナーに追加しようとすると、データベースへの保存に失敗します。
1.9.3-p194 :001 > trainer = Trainer.find(2)
Trainer Load (30.1ms) SELECT "trainers".* FROM "trainers" WHERE "trainers"."id" = ? LIMIT 1 [["id", 2]]
=> #<Trainer id: 2, name: "Noah Macejkovic", email: "trainer-1@mp-trainer.com", created_at: "2012-06-06 20:40:45", updated_at: "2012-06-06 20:40:45", password_digest: "$2a$10$bDL0ealWYdsxpN2jOyToCO9T/WKsI4I7WXdhRXQBvcP1...">
1.9.3-p194 :002 > client = Client.find(2)
Client Load (0.2ms) SELECT "clients".* FROM "clients" WHERE "clients"."id" = ? LIMIT 1 [["id", 2]]
=> #<Client id: 2, name: "Katherine Skiles V", email: "client-1@example.com", created_at: "2012-06-06 20:40:54", updated_at: "2012-06-06 20:40:54", password_digest: "$2a$10$47CUSOS3k5j1c.DjH2PP7uqHD6kM94rZHMco37X34li/...", trainer_id: nil>
1.9.3-p194 :003 > trainer.clients << client
(0.1ms) begin transaction
Client Exists (0.4ms) SELECT 1 FROM "clients" WHERE (LOWER("clients"."email") = LOWER('client-1@example.com') AND "clients"."id" != 2) LIMIT 1
(0.1ms) commit transaction
=> false
トランザクションの直後にクライアントにクエリを実行すると、trainer_id が表示されます
1.9.3-p194 :004 > client
=> #<Client id: 2, name: "Katherine Skiles V", email: "client-1@example.com", created_at: "2012-06-06 20:40:54", updated_at: "2012-06-06 20:40:54", password_digest: "$2a$10$47CUSOS3k5j1c.DjH2PP7uqHD6kM94rZHMco37X34li/...", trainer_id: 2>
しかし、データベースからリロードした後、trainer_id は nil です ( trainer.clients << client
.
1.9.3-p194 :006 > client.reload
Client Load (0.2ms) SELECT "clients".* FROM "clients" WHERE "clients"."id" = ? LIMIT 1 [["id", 2]]
=> #<Client id: 2, name: "Katherine Skiles V", email: "client-1@example.com", created_at: "2012-06-06 20:40:54", updated_at: "2012-06-06 20:40:54", password_digest: "$2a$10$47CUSOS3k5j1c.DjH2PP7uqHD6kM94rZHMco37X34li/...", trainer_id: nil>
したがって、問題の核心は、「データベースへのコミットが失敗するのはなぜですか?」ということです。