ActiveRelation需要嵌套的联接使用范围 [英] ActiveRelation that requires nested joins using scopes
问题描述
我是新来的轨道。有一个爆炸。查询API,虽然是给我 有些麻烦。我一直在放大,做了很多的东西非常快, 但是这是第一次我花了几个小时试图弄明白。 它不喜欢什么,我以前用过的 - 常规的SQL,或休眠状态, 或什么的。
I am new to rails. Having a blast. The query API though is giving me some trouble. I've been zooming and doing a lot of stuff very quickly, but this is the first time I have spent hours trying to figure it out. It's not like anything I've used before - regular SQL, or Hibernate, or whatever.
该模型我已经是pretty的简单。
The model I have is pretty simple.
- 系统PrivateMessage有许多收件人
- 在收件人有一个接收器(哪一类用户的)
- 在接收方也有场is_read'和'IS_DELETED
- A PrivateMessage has many Recipients
- A Recipient has a Receiver (which of class User)
- recipient also has fields for 'is_read' and 'is_deleted'
我的目标是建立一个查找所有未读,不会被删除查询 私人讯息给定用户。要做到这一点,我们需要加入 private_messages到收件人......然后'收件人'到 用户。
My goal is to build a query that finds all the unread and not deleted private messages for a given user. To accomplish this, we need to join 'private_messages' to 'recipients'... and then 'recipients' to 'users'.
下面是有关用户模型code:
Here's the relevant User model code:
has_many :sent_messages, :class_name => 'PrivateMessage', :foreign_key => 'sender_id' has_many :recipient_of_messages, :class_name => 'Recipient', :foreign_key => 'receiver_id' scope :by_id, lambda { |id| where(:id => id) }
我的收件人模式具有以下相关code:
My Recipient model has the following relevant code:
belongs_to :receiver, :class_name => 'User', :foreign_key => "receiver_id" belongs_to :private_message scope :unread, where(:is_read => false).where(:is_deleted => false) scope :by_receiver_id, lambda { |id| Recipient.joins(:receiver).merge(User.by_id(id)) } scope :unread_by_receiver_id, lambda { |id| unread.by_receiver_id(id) }
当单独测试,该工程100%。
When tested in isolation, this works 100%.
然而,当我code中的私人信息查询,我遇到的问题。
However, when I code the private message queries, I run into problems.
belongs_to :sender, :class_name => 'User' has_many :recipients, :class_name => 'Recipient' scope :sorted, order("private_messages.created_at desc") scope :non_deleted, where(:is_deleted_by_sender => false) scope :non_deleted_by_sender_id, lambda { |id| sorted.non_deleted.joins(:sender).merge(User.by_id(id)) } # this scope does not work scope :non_deleted_by_receiver_id, lambda { |id| sorted.joins(:recipients).merge(Recipient.by_receiver_id(id)) } scope :newest, sorted.limit(3) # this scope does not work either scope :newest_unread_by_receiver_id, lambda { |id| newest.joins(:recipients).merge(Recipient.unread_by_receiver_id(id)) }
当我尝试使用newest_unread_by_receiver_id'或'non_deleted_by_receiver_id',我得到了以下异常:
When I try and use 'newest_unread_by_receiver_id' or 'non_deleted_by_receiver_id', I get the following exception:
ActiveRecord::ConfigurationError: Association named 'receiver' was not found; perhaps you misspelled it?
这没有多大意义的,我......因为如果名字被拼写 错了,为什么没有当我测试它隔离失败?
This doesn't make much sense to me... because if the name was spelled wrong, why doesn't it fail when I test it isolation?
有人能帮助我吗?这一个是我发疯。有时 就是这样,我只是想在完整SQL编程或休眠QL所以我只能用它做:(
Can someone help me out please? This one is driving me nuts. At times like this, I just want to program in full sql or Hibernate QL so I could just be done with it :(
如果我只是接近问题完全错误的,那么我会AP preciate它,如果你只是让我知道这一点。我在使用作用域和ActiveRelation是一路前进中的Rails 3.1的IM pression。
If I'm just approaching the problem totally wrong, then I'd appreciate it if you just let me know that too. I am under the impression that using scopes and ActiveRelation was the way moving forward in Rails 3.1.
感谢
推荐答案
我可能会用这样的事情。我不停的范围分隔清晰。
I would probably use something like this. I kept scopes separate for clarity.
模型(改名PrivateMessage - >和收件人 - > MessageCopy):
Models (renamed PrivateMessage -> Message and Recipient -> MessageCopy):
class User < ActiveRecord::Base has_many :sent_messages, :class_name => "Message", :foreign_key => :sender_id has_many :sent_message_copies, :through => :sent_messages, :source => :message_copies has_many :received_messages, :through => :received_message_copies, :source => :message has_many :received_message_copies, :class_name => "MessageCopy", :foreign_key => :recipient_id end class Message < ActiveRecord::Base belongs_to :sender, :class_name => "User" has_many :message_copies has_many :recipients, :through => :message_copies end class MessageCopy < ActiveRecord::Base belongs_to :message belongs_to :recipient, :class_name => "User" scope :unread, where(:read => false) scope :undeleted, where(:deleted => false) scope :sent_to, lambda { |recipient| where(:recipient_id => recipient.id) } end
模式(迁移将采取太多的空间,在这里):
Schema (migrations would have taken too much space here):
ActiveRecord::Schema.define(:version => 20110503061008) do create_table "message_copies", :force => true do |t| t.boolean "read", :default => false t.boolean "deleted", :default => false t.integer "message_id" t.integer "recipient_id" end create_table "messages", :force => true do |t| t.string "title" t.integer "sender_id" end create_table "users", :force => true do |t| t.string "name" end end
- 修改
--edit
示例查询中使用联接返回的消息
Message.joins(:message_copies).where(:message_copies => {:read => false, :deleted => false, :recipient_id => 3})
信息范围重复使用于其他型号范围
scope :non_deleted_by_recipient, lambda { |recipient| joins(:message_copies).merge(MessageCopy.unread.undeleted.sent_to(recipient)) }
- EDIT2
--edit2
这Railscast具有很好的例子的两个连接和范围:
This Railscast has nice examples of both joins and scopes:
这篇关于ActiveRelation需要嵌套的联接使用范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!