Loading development environment (Rails 3.2.9)
irb(main):001:0> z = Zombie.last
Zombie Load (0.2ms) SELECT "zombies".* FROM "zombies" ORDER BY "zombies"."id" DESC LIMIT 1
=> #<Zombie id: 3, name: "n29", bit: nil, age: 29, created_at: "2012-12-14 03:05:25", updated_at: "2012-12-14 03:05:25", email: nil, rotting: false>
irb(main):002:0> z
=> #<Zombie id: 3, name: "n29", bit: nil, age: 29, created_at: "2012-12-14 03:05:25", updated_at: "2012-12-14 03:05:25", email: nil, rotting: false>
irb(main):003:0> z.id
=> 3
irb(main):004:0> z.id = 16
=> 16
irb(main):005:0> z.id
=> 16
irb(main):006:0> z.save
(0.2ms) begin transaction
(0.3ms) UPDATE "zombies" SET "updated_at" = '2012-12-14 03:58:25.810182' WHERE "zombies"."id" = 16
(0.1ms) commit transaction
=> true
class Zombie < ActiveRecord::Base
attr_accessible :age, :bit, :name
scope :fresh, where("age < 30")
has_one :brain, dependent: :destroy
end
class Brain < ActiveRecord::Base
attr_accessible :flavor, :status, :zombie_id
belongs_to :zombie, foreign_key: :zombie_id
end
绑定的 foreign_key 都被更新了 主表的主键反而没有
我的疑惑是 为什么不能修改主键 id 但却能修改另外一张表的外键。只是在练习中看到的例子 多尝试了几种操作 遇到一些问题 不太明白 不存在将这个逻辑放到什么项目里。只是练习
irb(main):013:0> z.brain
Brain Load (0.2ms) SELECT "brains".* FROM "brains" WHERE "brains"."zombie_id" = 3 LIMIT 1
=> #<Brain id: 2, zombie_id: 3, status: "fol", flavor: "Mud", created_at: "2012-12-14 03:30:17", updated_at: "2012-12-14 03:30:35">
irb(main):014:0>
irb(main):015:0*
irb(main):016:0*
irb(main):017:0*
irb(main):018:0*
irb(main):019:0* z.brain
=> #<Brain id: 2, zombie_id: 3, status: "fol", flavor: "Mud", created_at: "2012-12-14 03:30:17", updated_at: "2012-12-14 03:30:35">
irb(main):020:0> z.id
=> 3
irb(main):021:0> z.id = 5
=> 5
irb(main):022:0> z.save
(0.2ms) begin transaction
(0.2ms) UPDATE "zombies" SET "updated_at" = '2012-12-14 05:54:17.712562' WHERE "zombies"."id" = 5
(0.9ms) UPDATE "brains" SET "zombie_id" = 5, "updated_at" = '2012-12-14 05:54:17.715295' WHERE "brains"."id" = 2
(17.3ms) commit transaction
=> true
刚好我今天看见了这句话 避免改动缺省的 ActiveRecord(表的名字、主键,等等),除非你有一个非常好的理由(像是不受你控制的数据库)。 不知道对你有帮忙没有哦。Ruby is Big in China
#4 楼 @smallbug 谢谢~他说避免 应该是可以实现的 我的疑惑就在这里 既然这个操作没有实际更新到主键 id 那相对应的就不要修改外键的值 问题是 外键被修改了 主键没动 主键还是 3 不是 5 但外键已经被 update 成 3 了
sqlite> select * from zombies;
1|Caike Souza||27|2012-12-14 02:52:34.937489|2012-12-14 02:52:59.001395||f
2|neo||27|2012-12-14 03:05:10.530946|2012-12-14 03:05:10.530946||f
3|n29||29|2012-12-14 03:05:25.339947|2012-12-14 03:05:25.339947||f
sqlite> select * from brains;
2|5|fol|Mud|2012-12-14 03:30:17.379970|2012-12-14 05:54:17.715295
#5 楼 @ywjno 我为什么会想到这个事情 我们的业务表像提单之类的东西 ID 主键不是自增长 是有一个区段的的 比如 19 开头的是 NGB 宁波 22 开头的上海 10 月中旬做过的一次 DM 动作就是讲 NGB 的数据汇入到 SHA 里 相对的 ID 主键和从属的发票信息之类的东西都一并修改过来 实际场景中 还是会遇到这种事情的。我在 CodeSchool 今天看到的练习就是这样 via railsforzombie2 levels/2/challenges/8
那样的话,自己再加个字段比较合适吧,自己维护 ActiveRecord 的 id 太容易踩坑了;另外,我记得 ActiveRecord 里的 id,其实并不是数据库意义上的主键,只是看起来像而已
而且,这个练习看上去不是要你改主键或者外键的值哇,只是让你搞个 migration 而已:
rename_column :locations, :tweet_id, :tweeter_id
这种事情一般是 DBA 要干的事情,不是框架负责的事情,所以我想 rails 的 AR 没有实现响应的功能。DBA 不应该用 rails,直接写 sql 处理了。
#14 楼 @woody1983 我的意思是你不应该用 rails 的方法去改 AR 对象 ID,这样做意义不大啊,你要变更的“ID”应该是业务对象 ID,例如 user_id,order_id,... 你非要去改 AR 对象的 ID,我觉得只能走 sql 了,想不出来为什么要换这些号,除非你不喜欢这些数字从 1 开始。
#15 楼 @jimrokliu id 有时候是看 DW 设计的时候对于元数据怎么定义的 我们 OLAP 里面的 ID 规则是ID+Origin_ID
中间用 0 充满 18 位长度。这种设计有弊端也有好的一方面。另外 关于应该不应该 我就是这样 你说不能碰的东西我偏要碰一下看看会怎样 会爆虾米错误 也许有惊喜呢 呵呵
def update(attribute_names = @attributes.keys)
attributes_with_values = arel_attributes_values(false, false, attribute_names)
return 0 if attributes_with_values.empty?
klass = self.class
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values)
klass.connection.update stmt
end
def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
...
AR 特地吧 primary_key 排除了,就是不建议更新。一定要更新的话用 SQL 吧。
irb(main):007:0> Brain.all
Brain Load (0.3ms) SELECT "brains".* FROM "brains"
=> [#<Brain id: 2, zombie_id: 3, status: "fol", flavor: "Mud", created_at: "2012-12-14 03:30:17", updated_at: "2012-12-14 07:40:00">]
irb(main):008:0> z = Zombie.last
Zombie Load (0.3ms) SELECT "zombies".* FROM "zombies" ORDER BY "zombies"."id" DESC LIMIT 1
=> #<Zombie id: 3, name: "n29", bit: nil, age: 29, created_at: "2012-12-14 03:05:25", updated_at: "2012-12-14 03:05:25", email: nil, rotting: false, zombie_id: nil, id_zombier: nil>
irb(main):009:0> z.update_column(:id, 5)
SQL (24.6ms) UPDATE "zombies" SET "id" = 5 WHERE "zombies"."id" = 3
=> true
irb(main):010:0> z.save
(0.1ms) begin transaction
(0.3ms) commit transaction
=> true
irb(main):011:0> Zombie.all
Zombie Load (0.4ms) SELECT "zombies".* FROM "zombies"
=> [#<Zombie id: 1, name: "Caike Souza", bit: nil, age: 27, created_at: "2012-12-14 02:52:34", updated_at: "2012-12-14 02:52:59", email: nil, rotting: false, zombie_id: nil, id_zombier: nil>, #<Zombie id: 2, name: "neo", bit: nil, age: 27, created_at: "2012-12-14 03:05:10", updated_at: "2012-12-14 03:05:10", email: nil, rotting: false, zombie_id: nil, id_zombier: nil>, #<Zombie id: 5, name: "n29", bit: nil, age: 29, created_at: "2012-12-14 03:05:25", updated_at: "2012-12-14 03:05:25", email: nil, rotting: false, zombie_id: nil, id_zombier: nil>]
irb(main):012:0> Brain.all
Brain Load (0.3ms) SELECT "brains".* FROM "brains"
=> [#<Brain id: 2, zombie_id: 3, status: "fol", flavor: "Mud", created_at: "2012-12-14 03:30:17", updated_at: "2012-12-14 07:40:00">]
其实很明了了,AR 不支持更改 id,因为 id 的定义就是永远不改变的字段。
像订单号这样的数据应该另开一个字段,因为人工定义的字段没什么是不变的,身份证号就变过一次。
#27 楼 @woody1983 http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/belongs_to
似乎是 :primary_key,我还没用过
belongs_to :person, :primary_key => "name", :foreign_key => "person_name"
如果你用默认的 id 做关联,就没必要经常更新外键了。