我将用户的个人资料字段存储在单独的表中,并希望通过电子邮件地址查找用户(用于密码重置)。试图确定最佳方法,并遇到这种意外的行为不一致。
create_table(:users) do
String :username, primary_key: true
...
end
create_table(:user_fields) do
primary_key :id
foreign_key :user_id, :users, type: String, null: false
String :label, null: false
String :value, null: false
end
此版本有效(查找字段,急切加载它的关联用户,调用.all,取第一个):
irb(main):005:0> a = UserField.where(label: 'email', value: 'testuser@test.com').eager(:user).all[0]
I, [2015-09-29T17:54:06.273263 #147] INFO -- : (0.000176s) SELECT * FROM `user_fields` WHERE ((`label` = 'email') AND (`value` = 'testuser@test.com'))
I, [2015-09-29T17:54:06.273555 #147] INFO -- : (0.000109s) SELECT * FROM `users` WHERE (`users`.`username` IN ('testuser'))
=> #<UserField @values={:id=>2, :user_id=>"testuser", :label=>"email", :value=>"testuser@test.com"}>
irb(main):006:0> a.user
=> #<User @values={:username=>"testuser"}>
您可以看到两个查询(字段和用户)一起启动,当您尝试访问a.user时,数据已经加载。
但是当我尝试拨打.first代替.all:
irb(main):007:0> b = UserField.where(label: 'email', value: 'testuser@test.com').eager(:user).first
I, [2015-09-29T17:54:25.832064 #147] INFO -- : (0.000197s) SELECT * FROM `user_fields` WHERE ((`label` = 'email') AND (`value` = 'testuser@test.com')) LIMIT 1
=> #<UserField @values={:id=>2, :user_id=>"testuser", :label=>"email", :value=>"testuser@test.com"}>
irb(main):008:0> b.user
I, [2015-09-29T17:54:27.887718 #147] INFO -- : (0.000172s) SELECT * FROM `users` WHERE (`username` = 'testuser') LIMIT 1
=> #<User @values={:username=>"testuser"}>
急切加载失败 - 在您尝试使用b.user引用它之前,它不会启动用户对象的第二个查询。
我在这里没有了解续集gem API的内容?什么是基于其关联模型的属性加载模型实例的最佳方法? (通过电子邮件地址查找用户)
答案 0 :(得分:1)
只有在加载多个对象时才有意义加载。并且为了急切加载,您首先需要所有当前对象,以便在一个查询中获取所有关联对象。使用each
,您无法首先访问所有当前对象,因为您正在迭代它们。
如果你希望Sequel在内部为你处理事情,你可以使用eager_each
插件,但请注意,它会使dataset.first
为急切加载的数据集执行与dataset.all.first
类似的操作。但是如果你只需要一个对象,那么最好不要急于加载,如果你需要急切地加载多个对象,最好调用all
。