【问题标题】:Rails many-to-many existence queryRails 多对多存在查询
【发布时间】:2012-03-30 18:48:27
【问题描述】:

一种 ruby​​-noob 活动记录查询问题:

Magazine
  has_many :subscriptions

User
  has_many :subscriptions

Subscription
  belongs_to :user
  belongs_to :magazine

在控制器中,我想有效地询问 current_user 是否订阅了 a_magazine。我觉得应该是这样的……

Subscription.where("user_id = ? and magazine_id = ?", current_user.id, a_magazine.id).count > 0

a) 看起来对吗? b) 是否有更有效的方法(假设 FK 上的索引) c) 在风格上,是否有更可接受或更简洁的方法?

提前谢谢...

【问题讨论】:

  • B) 假设 FK 上的索引这个查询应该非常有效(并且可能是最有效的)
  • 嗨@Aldo'xoen'Giambelluca 实际上在我的has_many through 协会中我也有类似的情况,我现在正在使用这个 current_customer .id).任何? %> 在渲染 Products#index 视图时,了解哪些列出的产品在记录的Customer 愿望清单中并突出显示它们。但我担心的是性能;当产品列表很大时,这是一个好方法吗?还是有另一个更有效的查询不影响性能?

标签: sql ruby-on-rails ruby activerecord


【解决方案1】:

更简洁的方法是使用哈希方法来声明查询,这种方法更容易阅读并且出错的机会更少:

Subscription.where(:user_id => current_user.id, :magazine_id => a_magazine.id).any?

您还可以添加:through 关系以根据用户或杂志相应地进行检查。

class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :magazines, :through => :subscriptions
end

这使得匹配测试变得非常容易:

user = User.find(1)
user.magazines.where(:magazine_id => magazine_id).any?

【讨论】:

  • 我想要一个逗号分隔散列,还是一个连词“and”?不过,我想无论哪种方式,我都应该利用直通,并使用其他公式。
  • 您好!我有类似的情况,我现在在渲染Products#index 视图时使用这个&lt;% if product.wishlist.where(:customer_id =&gt; current_customer.id).any? %&gt; 来了解哪些列出的产品在记录的Customer 愿望清单中并突出显示它们。但我担心的是性能;当产品列表时,这是一个好方法吗?还是有另一个更有效的查询不影响性能?
  • 这是一个经典的 N+1 查询情况。您可能想要做的是使用某种查询预加载愿望列表中与products 列表重叠的所有product_id 值。返回 ID 的模型级类方法是放置它的好地方。
【解决方案2】:

看起来像经典的 has_many :through 对我的联想。见这里:

http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association

基本上,您的用户通过订阅拥有_many 杂志,并且您的杂志也通过订阅拥有许多用户。建立这些关联后,您的代码应该会简化。

【讨论】:

    【解决方案3】:

    您应该将关联更改为has_many :through 关系。这样你就有了一个可以通过两个模型引用的模型。

    class Magazine < ActiveRecord::Base
      has_many :users, :through => :subscriptions
    end
    
    class User < ActiveRecord::Base
      has_many :magazines, :through => :subscriptions
    end
    
    class Subscription < ActiveRecord::Base
      belongs_to :user
      belongs_to :magazine
    end
    

    现在您可以检查 SubscriptionsUser 拥有的像这样...

    User.find(current_user.id).subscriptions # => Returns a list of Magazine id's
    

    您可以通过Subscription 像这样检查User 是否有Magazine...

    User.find(current_user.id).subscriptions.find_by_magazine_id(1).any? 
    

    【讨论】:

    • 最后一行不是用户,而是订阅。应该是@subscription 而不是@user。您也可以使用find_by_magazine_id(1)where(:magazine_id =&gt; 1),这样更不容易搞砸。
    • 我并不是要包含一个实例变量,感谢您了解这一点。还要感谢您指出额外的方法! +1
    猜你喜欢
    • 2020-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多