【问题标题】:Selecting models through Rails relations?通过 Rails 关系选择模型?
【发布时间】:2013-09-30 21:59:51
【问题描述】:

我有这些(简化的)模型:

Address
public (Boolean)
has_one :group_member

Group
has_many :Group_Members
belongs_to :User

Group_Member
belongs_to :group
belongs_to :address

User
has_many :groups

我想选择public 为真的所有地址以及用户可以通过组访问的所有地址。

我认为是这样的:

Address.where(public: TRUE).joins(:group_member)

我在附近吗?

如果对任何人有帮助,我将使用 Rails 4 和 PostgreSQL 作为我的数据库。

【问题讨论】:

  • 你的意思是Address而不是Model?
  • 哦,是的,我做到了,感谢您的关注! :)
  • public 是 ruby​​ 中的保留字,你可能想使用 is_public 之类的属性。
  • 谢谢@AndrewKuklewicz,这可能会给我带来很多痛苦
  • 您是否尝试为特定用户或任何用户访问addresses

标签: sql ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

我认为这会奏效:

Address.joins(group_member: :group).where(is_public: true, groups: {user_id: 12345})

让我们分解一下。

首先我们调用Address 模型,b/c 这就是我们想要返回的。

.joins(:group_member) 将通过Address has_one :group_member 关系将地址加入group_members

但是,我们其实想更进一步,将groupgroup_member连接起来,所以我们使用嵌套连接,这就是为什么它看起来像这样joins(group_member: :group)表示我们加入地址-> group_member,然后是 group_member -> 组。

接下来是 where 子句。有两个条件,我们想要:

  1. 仅限公共地址,在地址上显示为一列,因此我们添加以下内容: .where(is_public: true)
  2. 我们只需要特定用户与组连接的位置(以及它的 group_members 和地址)。为此,我们需要添加一个嵌套的 where 子句,例如 groups: {user_id: 12345}

结合这些的结果是:

where(is_public: true, groups: {user_id: 12345})

所以总的来说,上面的代码行应该得到你想要的。

【讨论】:

  • “在地址上找不到名为“组”的关联”是我得到的
  • 因此您需要添加该关系的另一端 - 地址 belongs_to :group_member
  • 但是一个地址没有任何组。你能解释一下你的代码吗?
  • 啊,没有嵌套连接,已编辑。另外,看看这个例子:guides.rubyonrails.org/…
  • 那没有任何意义。如果 GroupMember 有一个地址,那么地址必须有一个 group_member_id。如果是 GroupMember belongs_to 地址,那么 GroupMember 上会有一个 address_id。 guides.rubyonrails.org/… 所以用 GroupMember 替换 Supplier,用 Address 替换 Account - 明白我的意思吗?您的钥匙或您的关系有误。
【解决方案2】:

试试下面的 -- 这不是一个单一的查询,但我认为它比一个带有大连接表的单一查询要好:

public_addresses = Address.where(is_public: true)
# =>  get all public addresses

user_addresses = current_user.groups.includes(:group_members => :address).
                # includes is to eager load records to avoid N+1 queries
                flat_map{|g| g.group_members.map(&:address)}
                # inner block returns array of addresses for each group
                # flat_map converts the array of arrays to single level 
# => get all addresses associated with the user


all_addresses = (public_addresses + user_addresses).uniq
# =>  remove duplicates

为加快查询速度,为较慢的查询添加索引。例如

   add_index :groups, :user_id
   # this speeds up finding groups for a given user

   add_index :group_members, :group_id
   # this speeds up finding group_members for a given group

   add_index :addresses, :group_member_id
   # this speeds up finding addresses for a given group_member

其他选项是使用join 表获取user_addresses

   user_addresses = Address.joins(group_member: group).where(groups: {user_id: current_user.id} )

【讨论】:

  • "找不到关联 :group_members in mode User"
  • 你试过Useruser吗?
  • 更新了,更清楚了...current_user是登录的用户
  • @DanAndreasson 查看文档here...这需要进行数据库迁移。
  • ohhh..很多关于此的文章,例如看到这个one
猜你喜欢
  • 2010-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-21
  • 1970-01-01
相关资源
最近更新 更多