使用“has Many through”进行急切加载——我需要阿雷尔吗?
我有三个表:users
、members
、projects
。中间是一个连接表,表达了其他两个表之间的多通关系;它有一些有趣的属性,包括 join_code
和 activated
。
更广泛地说:
class User < ActiveRecord::Base
has_many :members
has_many :projects, :through => :members
end
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :project
# has a column called join_code
# has a column called activated
# Note that this class can be thought of as "membership"
end
class Project < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
end
目标:给定一个特定用户,我想要一个查询来获取所有项目,并立即加载仅将这些项目链接到该用户的成员记录。
到目前为止,我在 user.rb
中有一个执行查询的方法:
def live_projects
self.projects.order("projects.name").includes(:members).where(:members => {:join_code => nil, :activated => true})
end
但这还不够。然后我希望能够在视图代码中执行此操作:
<% current_user.live_projects.each do |project| %>
<li project_id="<%= project.id %>">
<% member = project.member %>
(Do something with that member record here)
<%= project.name %>
<% end %>
</li>
<% end %>
在这里,通常我有 project.members
,但在我的上下文中,我只对那个 感兴趣 链接回用户的成员记录。
我认为原始 SQL 应该是这样的
select projects.*, members.*
from projects inner join members on projects.id = members.project_id
where members.user_id = X and members.join_code is null and members.activated = 't';
如何在 Arel (或 ActiveRecord)中做到这一点?
I have three tables: users
, members
, projects
. The middle is a join table expressing a has-many-through between the other two tables; and it has some attributes of interest, including join_code
and activated
.
More expansively:
class User < ActiveRecord::Base
has_many :members
has_many :projects, :through => :members
end
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :project
# has a column called join_code
# has a column called activated
# Note that this class can be thought of as "membership"
end
class Project < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
end
Goal: Given a particular user, I want a query that will get all the projects, and eager load only the member records that link those projects to the user.
So far I have this method in user.rb
that does a query:
def live_projects
self.projects.order("projects.name").includes(:members).where(:members => {:join_code => nil, :activated => true})
end
But it's not enough. I'd like to then be able to do this in the view code:
<% current_user.live_projects.each do |project| %>
<li project_id="<%= project.id %>">
<% member = project.member %>
(Do something with that member record here)
<%= project.name %>
<% end %>
</li>
<% end %>
Here, normally, I'd have project.members
, but in my context I'm only interested in that one member record that links back to the user.
Here is what I think the raw SQL should look like
select projects.*, members.*
from projects inner join members on projects.id = members.project_id
where members.user_id = X and members.join_code is null and members.activated = 't';
How to do that in Arel (or ActiveRecord)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我在这里可能有一些答案,即我编写的 ActiveRecord 代码看起来相当合理。再次,这是该查询:
在使用示例数据运行 UI 时,它会从 Rails 服务器生成此输出:
然后在视图代码中我可以执行以下操作:
用于获取成员记录的表达式在视图中非常难看,但是 < code>select 是一个
Array
方法,而不是查询,除了上面显示的两个之外,Rails 服务器的输出中不会出现任何额外的数据库命中。因此我想我的 n+1 问题已经解决了。I may have something of an answer here, namely that the
ActiveRecord
code I wrote seems pretty reasonable. Again, here's that query:On a run through the UI with sample data it generates this output from Rails server:
Then later in the view code I can do this:
That expression to get the member record is pretty ugly in the view, but
select
is anArray
method, not a query, and no extra DB hits other than the two shown above appear in the output from Rails server. Thus I guess my n+1 problem is solved.在
Project
类上添加一个名为live_members
的关联。在
User
类上添加一个名为live_projects
的关联。现在您可以:
Add an association called
live_members
on theProject
class.Add an association called
live_projects
on theUser
class.Now you can:
您似乎希望最多有一个活跃成员将每个用户链接到一个项目。如果是这种情况,以下操作应该有效:
在
member.rb
中:在
user.rb
中:在您的视图中:
如果您想添加额外的连接供您使用统计你可以这样做:
It seems that you expect there to be at most one active member linking each user to a project. If this is the case the following should work:
In
member.rb
:In
user.rb
:In your view:
If you then want to add an extra join for your usage stats you can do this: