Rails 怎么把几个 model 合在一起

jeffhappily · 2017年10月13日 · 最后由 Rei 回复于 2017年10月16日 · 1745 次阅读

我有一个Usermodel,User有几个 associated 的 model,然后通过 User,我把几个 model 合在一起,如下

tables = [:a, :b, :c, :d]

result = tables.map do |t|
  @user.send(t)
end.flatten

但我要的不仅仅是 model,而是特定的资料,例如说

class A
  def data
    {
      name: name,
      age: age
     }
  end
end

class B
  def data
    {
      name: name,
      height: height
     }
  end
end

然后查询会是这样

tables = [:a, :b, :c, :d]

result = tables.map do |t|
  @user.send(t).map {|d| d.data}
end.flatten

AB都有 data,但内容不完全一样, 这样的话,如果我做的是一个庞大的查询的话,要每个 model 轮流去算这个 data(data 可能需要计算,不是单纯的属性),整个查询就会非常慢。

想请问有什么办法优化吗?例如把 data 存进资料库?

Rei 回复

我明白你说什么

@user = User.includes(:a, :b, :c, :d).find(1)

tables = [:a, :b, :c, :d]

result = tables.map do |t|
  @user.send(t).map {|d| d.data}
end.flatten

这样可以减少 query 的数量,对吧? 那么对于 data,又该怎么处理?因为 data 是一个 method,所以如果我有 1000 个 a,我 map 的时候@user.send(t).map {|d| d.data},就要调用 data1000 次了吧?

jeffhappily 回复

举个现实的例子,我想不通要轮流查 a b c 的意义。

对于如何避免重新计算 data 这一点,可以把计算结果放库里。

Rei 回复

我的应用是关于 healthcare 的,所以user会有prescription,consultation等不同的 model,我这样做是要把他们合在一起按时间顺序排列出来

jeffhappily 回复

可以采用 join(把几张表 join 起来,一起返回结果)等办法吧? 一个 user 会有几个 prescription, consultation 这样的相关数据?不会很多的吧?

做好 index,然后用 join。通过 DB-API 会比在上层代码里处理更快。

ruby 也就是工具而已,不用被限制。用惯了筷子喝汤也用筷子不成?

Rails 里面有 join 写法的,会自动生成相关 SQL 的。在这点上,Rails 没有限制,是提供了喝汤用的勺子的。

jeffhappily 回复

可以增加一张表,解决查和排序,同时储存 data 避免运算

{
  user_id
  source_type
  source_id
  data
  created_at
  updated_at
}

@doosolar @lotusfire 用 join 的话,具体是怎样呢?我对 sql 了解不深,join 我试了,但好像达不到我的需求。相关数据挺多的,不只我说的两个,总共有 5 个关联的 model

Rei 回复

这样的话,以后每创建一个数据,就得在这个新的表添加一行对吧?

jeffhappily 回复

是的。有更新的话,也要更新 data。

Rei 回复

其实 data 是为了 view 的,内容大概是

{
  id: 1,
  title: "Title",
  icon: "icon",
  btn: "<a href='..'>button</a>"
}

但里面有牵扯到其他模组的逻辑,这样的话,存进库会不会是最好的方案呢? 还是说在前端处理会比较好呢?

jeffhappily 回复

那可以用片段缓存。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号