不确定我的用户/位置与Rails 4的关联

时间:2013-05-24 12:35:20

标签: ruby-on-rails has-many belongs-to model-associations ruby-on-rails-4

我创建了一个用户和一个位置模型(以及一个产品模型,但一次只有一个问题),当我在玩控制台时,我对一些结果感到惊讶。

模型

Class User < ActiveRecord::Base
# Before saving filters
  before_save { self.email = email.downcase }
  before_save :create_remember_token

# Validations
  validates :name, presence: true,
                   length: { maximum: 50 }
  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 }
  has_secure_password
  validates :password, length: { minimum: 6 }
  validates :password_confirmation, presence: true

# Associations
  has_many :owned_products, class_name: "Product",
                            foreign_key: "owner_id",
                            dependent: :destroy
  has_many :borrowed_products, class_name: "Product",
                               foreign_key: "borrower_id"
  belongs_to :location

  private

    def create_remember_token
      self.remember_token = SecureRandom.urlsafe_base64
    end
end


Class Product < ActiveRecord::Base
  validates :name, presence: true,
                   length: { maximum: 50 }
  validates :owner, presence: true

  belongs_to :owner, class_name: "User", foreign_key: "owner_id"
  belongs_to :borrower, class_name: "User", foreign_key: "borrower_id"
  belongs_to :location
end

Class Location < ActiveRecord::Base
  has_many :users
  has_many :products
end

迁移

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :email
      t.string :password_digest
      t.string :remember_token
      t.integer :location_id

      t.timestamps
    end
    add_index :users, :email, unique: true
    add_index :users, :remember_token
    add_index :users, :location_id
  end
end

class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.string :name
      t.integer :location_id

      t.timestamps
    end
    add_index :products, :location_id
  end
end

class CreateLocations < ActiveRecord::Migration
  def change
    create_table :locations do |t|
      t.string :address

      t.timestamps
    end
  end
end

位置属性是可访问的

class UsersController < ApplicationController
    .
    .
    .
  private

    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation, :location, :location_attributes)
    end
end

然后我去我的控制台输入:

User.create(name: "Wahou", email: "wahou@bim.com", password: "motdepasse", password_confirmation: "motdepasse")

是什么让我:

(0.2ms)  begin transaction
User Exists (0.4ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('wahou@bim.com') LIMIT 1
Binary data inserted for `string` type on column `password_digest`  SQL (1.1ms)  INSERT INTO "users" ("created_at", "email", "name", "password_digest", "remember_token", "updated_at") VALUES (?, ?, ?, ?, ?, ?)  [["created_at", Fri, 24 May 2013 12:27:38 UTC +00:00], ["email", "wahou@bim.com"], ["name", "Wahou"], ["password_digest", "$2a$10$OhJ7SLA.vxO4N8IkZAXXQOibYQoX6G6E9/mGgmDpm8Hj48p8riDE."], ["remember_token", "-O72ULpG2tjrZSSi0BFB5A"], ["updated_at", Fri, 24 May 2013 12:27:38 UTC +00:00]]
(148.6ms)  commit transaction
=> #<User id: 1, name: "Wahou", email: "wahou@bim.com", password_digest: "$2a$10$OhJ7SLA.vxO4N8IkZAXXQOibYQoX6G6E9/mGgmDpm8Hj...", remember_token: "-O72ULpG2tjrZSSi0BFB5A", admin: false, location_id: nil, created_at: "2013-05-24 12:27:38", updated_at: "2013-05-24 12:27:38"> 

然后我输入:

Location.create(address: "1, rue des prises de tête - Paris")

这给了我:

(0.2ms)  begin transaction
SQL (6.0ms)  INSERT INTO "locations" ("address", "created_at", "updated_at") VALUES (?, ?, ?)  [["address", "1, rue des prises de tête - Paris"], ["created_at", Fri, 24 May 2013 12:27:22 UTC +00:00], ["updated_at", Fri, 24 May 2013 12:27:22 UTC +00:00]]
(121.6ms)  commit transaction
=> #<Location id: 1, address: "1, rue des prises de tête - Paris", street: nil, city: nil, postal_code: nil, country: nil, longitude: nil, latitude: nil, created_at: "2013-05-24 12:27:22", updated_at: "2013-05-24 12:27:22"> 

所以,完全有信心,我这样做:

User.first.location = Location.first

这给了我:

User Load (0.5ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
Location Load (0.4ms)  SELECT "locations".* FROM "locations" ORDER BY "locations"."id" ASC LIMIT 1
=> #<Location id: 1, address: "1, rue des prises de tête - Paris", street: nil, city: nil, postal_code: nil, country: nil, longitude: nil, latitude: nil, created_at: "2013-05-24 12:27:22", updated_at: "2013-05-24 12:27:22"> 

当我输入User.first.location时,它会给我nil

所以我想我忘记了某个地方。你有什么想法吗?

(如果您将产品替换为User,则完全相同......)


修改

我尝试仅键入User.first.location_id = 1User.first.location始终为nil

我找到定义用户位置的唯一方法是使用位置创建他,就像那样:Location.first.users.create(name: "Wahou", email: "wahou@bim.com", password: "motdepasse", password_confirmation: "motdepasse")。然后,它可以工作......但是当我想更新用户的位置时,我该怎么办?


编辑2

当我输入

u = User.first

我看到第一个用户被抓住了:

User Load (0.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> #<User id: 2, name: "Numero1 Person", email: "numero1@person.com", password_digest: "$2a$10$sNwoTjOL4eqW.clxbM5FcuiE0AmPgzr8Kz0ewXgddAvP...", remember_token: "OQ2ZnLhPutwePTqn49r5PQ", admin: false, location_id: 2, created_at: "2013-05-29 07:59:13", updated_at: "2013-05-29 09:22:00"> 

然后我将Location.first影响到我的第一个用户的位置:

u.location = Location.first

我看到抓住了第一个位置:

Location Load (0.4ms)  SELECT "locations".* FROM "locations" ORDER BY "locations"."id" ASC LIMIT 1
=> #<Location id: 1, address: "1, rue longue - 99999 LOIN - France", street: "1, rue longue", city: "LOIN", postal_code: 99999, country: "France", longitude: nil, latitude: nil, created_at: "2013-05-29 07:59:38", updated_at: "2013-05-29 07:59:38"> 

但是当我想保存它时......

u.save

......它不起作用!

(0.1ms)  begin transaction
User Exists (0.4ms)  SELECT 1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('numero1@person.com') AND "users"."id" != 2) LIMIT 1
(0.2ms)  rollback transaction
=> false 

编辑3

如果我尝试输入以下代码......

User.first.update_attributes(location: Location.first)

它告诉我:

User Load (0.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
Location Load (0.3ms)  SELECT "locations".* FROM "locations" ORDER BY "locations"."id" ASC LIMIT 1
 (0.1ms)  begin transaction
User Exists (0.4ms)  SELECT 1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('numero1@person.com') AND "users"."id" != 2) LIMIT 1
 (0.2ms)  rollback transaction
=> false 

解决

对我感到羞耻!我忘了在update_attributes中添加密码和password_confirmation。如果我这样做,它就有效!

这是正确的代码:

User.first.update_attributes(password: "password", password_confirmation: "password", location: Location.first)

2 个答案:

答案 0 :(得分:1)

@Aurel给了你正确的提示。有关解释:

执行

User.first.location_id = 1

将第一个用户加载到临时对象中,然后设置location_id,然后将其抛出而不保存。这就是为什么你的改变不持久。

@斯坦的

u= User.first
u.location = Location.first 
u.save

将第一个用户加载到u,设置u的位置,然后保存以使其持久。之后

User.first.location

给出对象Location.first

另一种方式是用户update_attribut,它设置属性并保存更改,所以

User.first.update_attribute :location, Location.first

也有效并且使更改持久。

答案 1 :(得分:0)

是的,你忘了保存更改。

u = User.first # => <User id: 1, name: "Wahou"....
l = Location.first #=> <Location id: 1, address: "1 rue.....

# set the location
u.location = l

#Save changes
u.save

#profit
User.first.location