开发者

How do I use Rails to find one has_many but not the other?

Message has_many user_messages. It has two.

1 UserMessage will have the sender as user_id

The other UserMessage will have the receiver as user_id

Knowing one user, how can I, for any message, find the other?

Here's what I tried as a method to the Message class, but it fails:

 32   def other_user(one_user开发者_Go百科)      
 33     um = self.user_messages
 34     um.each do |user_message|
 35       
 36       output_user = User.find(user_message.user_id) unless user_message.user_id == one_user.id
 37     end
 38     
 39     return output_user
 40   end


This could be implemented as an association enhancement. This will be efficient for high-volume of messages as it pushes processing to DB.

class User < ActiveRecord::Base

    has_many :sent_messages, :class_name => "Message", :foreign_key => "sender_id"
    has_many :receivers, :through => :sent_messages, :source => :receiver do 
        def for_message(message_id)
            where("messages.id = ?", message_id)
        end
    end

    # Another association mapping for received_messages

end


class Message < ActiveRecord::Base

    belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
    belongs_to :receiver, :class_name => "User", :foreign_key => "receiver_id"

end


#Usage
User.first.sent_messages

#all users received messages from first user
User.first.receivers

#all users received messages from first user for message of message_id
User.first.receivers.for_message(message_id)


It seems like there should be a better definition of who is the sender and who is the receiver, but in the meantime, what about:

def other_user(one_user)
  user_messages.reject do |msg|
    msg.user_id == one_user.id
  end.first.user
end

It takes the set of user_messages, filters out the one that belongs to one_user. There should be one left in the array, so pick it out and return the user attached to it.

EDIT

I might not understand all your requirements, but I'd probably just add a sender_id and receiver_id directly to Message and remove the UserMessage join table. Then you could define the relationship like:

class User
  has_many :sent_messages, :class_name => 'Message', :foreign_key => 'sender_id'
  has_many :received_messages, :class_name => 'Message', :foreign_key => 'receiver_id'
end

class Message
  belongs_to :sender, :class_name => 'User'
  belongs_to :recipient, :class_name => 'User'
end

EDIT 2

If you want the intermediate table for tracking user-specific states, you could look into using STI to subclass UserMessage as SentMessageLink and ReceivedMessageLink (those names are not awesome -- but you get the idea), then you could use has_many :through.

class SentMessageLink < UserMessage
  belongs_to :sender, :class_name => 'User'
  belongs_to :message
end

class User
  has_many :sent_message_links
  has_many :sent_messages, :through => :sent_message_links
end

class Message
  has_one :sent_message_link
  has_one :sender, :through => :sent_message_link
end

with similar code for received messages. Then you should be able to access sender and receiver right from the message.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜