将复杂的has_many关系移植到Rails> 4.1(没有finder_sql)

我正在将Rails应用程序移植到Rails 4.2。 这个Rails应用程序在关联中包含一些相当复杂的手动SQL代码 – 部分原因是DB优化(例如子选择而不是JOIN),部分原因是由于在编写时没有可行的替代方案(Rails 3.0),部分原因是由于缺乏知识(我希望,至少 – 这很容易解决)。

示例:InternalMessage类。 可以在用户之间发送消息(InternalMessage的收件人和消息的“删除”,存储在InternalMessagesRecipients中,因为可以有几个),并且可以读取,回复,转发和删除它们。 该关联看起来像这样:

class User  "SELECT DISTINCT(internal_messages.id), internal_messages.* FROM internal_messages " + ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' + ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}', :counter_sql => 'SELECT count(DISTINCT(internal_messages.id)) FROM internal_messages ' + ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' + ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}' # ... end 

关键部分是最后的“OR”子句 – 通过这种关联,我希望获得接收和发送的消息,这些消息与用户表单独连接:

  has_many :sent_messages, -> { where(:sender_deleted_at => nil) }, :class_name => 'InternalMessage', :foreign_key => 'sender_id' #, :include => :sender has_many :internal_messages_recipients, :foreign_key => 'recipient_id' has_many :rcvd_messages, :through => :internal_messages_recipients, :source => :internal_message, :class_name => 'InternalMessage' 

因为InternalMessage可能有几个收件人(也可以自己发送给发件人)。

问:如何将此finder_sql到兼容Rails 4.2的has_many定义?

更新

我刚才了解到这没有道理。 has_many关系必须至少在一个方向上具有内射连接,因此SQL子句中的“OR”没有意义。 CREATE操作应该如何确定创建新记录时要满足哪个条件? 这种关系只能按定义读取,因此它不是has_many关系。

在这种情况下,一个简单的类方法(或范围)将是正确的答案而不是has_many 。 要连接几个查询的结果使用类似的东西

 def internal_messages InternalMessage.where( id: sent_message_ids + received_message_ids) end 

保持结果对象可链接(即@user.internal_messages.by_date等)

将包含SQL字符串的proc作为作用域传递。

 has_many :internal_messages, -> { proc { "SELECT DISTINCT(internal_messages.id), internal_messages.* FROM internal_messages " + ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' + ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}' } }