我有一个类型A的实例,其中包含了很多Bs。当A.foo = value
方法被调用时,我实际上想要编写一个委托给foo的方法=调用A的第一个B。
class A < ActiveRecord::Base
has_many :bs, autosave: true
def foo
bs.first.foo
end
def foo=(val)
bs.first.foo = val
end
end
class B < ActiveRecord::Base
belongs_to A
end
rails generate model A
rails generate model B a:references foo:string
2.3.0 :001 > a = A.create!
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "as" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2016-10-08 18:03:18.255107"], ["updated_at", "2016-10-08 18:03:18.255107"]]
(7.8ms) commit transaction
=> #<A id: 1, created_at: "2016-10-08 18:03:18", updated_at: "2016-10-08 18:03:18">
创建一个A并将其命名为a
。
2.3.0 :002 > b = B.create!(a: a, foo: "initial")
(0.4ms) begin transaction
SQL (0.4ms) INSERT INTO "bs" ("a_id", "foo", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["a_id", 1], ["foo", "initial"], ["created_at", "2016-10-08 18:03:40.658035"], ["updated_at", "2016-10-08 18:03:40.658035"]]
(8.3ms) commit transaction
=> #<B id: 1, a_id: 1, foo: "initial", created_at: "2016-10-08 18:03:40", updated_at: "2016-10-08 18:03:40">
创建一个B并将其命名为b
。让它成为A的孩子。将它的foo属性设置为&#34; initial&#34;。
2.3.0 :003 > a.reload.foo
A Load (0.2ms) SELECT "as".* FROM "as" WHERE "as"."id" = ? LIMIT 1 [["id", 1]]
B Load (0.2ms) SELECT "bs".* FROM "bs" WHERE "bs"."a_id" = ? ORDER BY "bs"."id" ASC LIMIT 1 [["a_id", 1]]
=> "initial"
检查a
是否看到了新生儿foo
:是的。正如所料。
2.3.0 :004 > a.foo = "set"
B Load (0.1ms) SELECT "bs".* FROM "bs" WHERE "bs"."a_id" = ? ORDER BY "bs"."id" ASC LIMIT 1 [["a_id", 1]]
=> "set"
2.3.0 :005 > a.foo
B Load (0.4ms) SELECT "bs".* FROM "bs" WHERE "bs"."a_id" = ? ORDER BY "bs"."id" ASC LIMIT 1 [["a_id", 1]]
=> "initial"
Whaaat?我刚刚打电话给a.foo = "set"
。现在,当我再次致电a.foo
读取值时,我得到"initial"
?这不是has_one
关系的工作方式。为什么ActiveRecord每次都会从数据库重新加载,而不是缓存它的查询?
最终,我打算致电a.save!
,让它自动保存到b。但如果这种关系对每一个未决的变化都有失忆,那就不可能了。这是怎么回事?!
答案 0 :(得分:1)
在A和B之间设置has_one
关系,并将foo委托给has_one
关联。
class A
has_many :bs
has_one :first_b, -> { first },
class_name: 'B'
delegate :foo, to: :first_b
end
要避免查询B,您可以使用.joins
, includes
or eager_load
。