модель сообщения пользователя в рельсах 3

Я построил следующую модель для обработки обмена сообщениями пользователя:

 create_table "messages", :force => true do |t|
    t.integer  "source_id"
    t.integer  "destination_id"
    t.string   "object"
    t.string   "body"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

Вот его ассоциации:

class Message < ActiveRecord::Base
  belongs_to :sender, :class_name=>'User', :foreign_key=>'source_id'
  belongs_to :reciever, :class_name=>'User', :foreign_key=>'destination_id'
end

И эти другие ассоциации с другой стороны (модель пользователя):

 has_many :sent_messages, :class_name=> 'Message', :foreign_key=>'source_id', :dependent=>:destroy
  has_many :recieved_messages, :class_name=> 'Message', :foreign_key=>'destination_id', :dependent=>:destroy

Модель правильная и работает правильно, фактически из сообщения я могу узнать, кто является отправителем и кто является получателем, а от пользователя я могу получить все отправленные и полученные сообщения. К сожалению, он не обрабатывает любую ситуацию: что, если получатель или отправитель удалят сообщение? Сообщение уникально, поэтому оно исчезает с обеих сторон (плохо). Как узнать, прочитала ли уже сообщение одна из сторон? Любое предложение ? Как вы думаете, я должен перепланировать модель? Tnx


person Joe    schedule 28.02.2011    source источник


Ответы (3)


это хорошая проблема! Я бы смоделировал это, чтобы максимально сравнить его с моделью электронной почты. Таким образом, сообщение всегда принадлежит одному пользователю, и оно либо отправлено, либо получено.

Короче:

 create_table "messages", :force => true do |t|
    t.integer  :user_id
    t.string   :subject
    t.string   :body
    t.boolean  :sent
  end

И модель хотела бы:

class Message < ActiveRecord::Base
  belongs_to :user

  scope :sent, where(:sent => true)
  scope :received, where(:sent => false)

end

И в пользователе:

class User    
  has_many :messages
end

Затем вы просто сможете запросить все отправленные сообщения с помощью

user.messages.sent

и полученные сообщения

user.messages.received

Отправка сообщения становится немного сложнее:

class Message

  def send_message(from, recipients)
    recipients.each do |recipient|
      msg = self.clone
      msg.sent = false
      msg.user_id = recipient
      msg.save
    end
    self.update_attributes :user_id => from.id, :sent => true
  end   
end

или что-то в этом роде: вы копируете сообщение и прикрепляете его ко всем получателям и, наконец, делаете исходное сообщение отправленным сообщением.

Таким образом, каждый пользователь имеет полный контроль над сообщением.

Возможные улучшения:

  • также сохраняйте явную ссылку на отправителя и получателя (ов) в сообщении, чтобы иметь возможность разрешать ответы и прочее.
  • вместо того, чтобы работать с одним логическим значением, может быть, разрешить работу с папками?

Надеюсь это поможет.

person nathanvda    schedule 02.05.2011
comment
Отличный материал! Однако для Rails 3+ вы захотите использовать self.dup. - person DaynaJuliana; 24.01.2015

Вы можете добавить два логических значения, чтобы пометить сообщение как удаленное как для отправителя, так и для получателя. Затем после установки любого из них проверьте, можно ли удалить сообщение навсегда.

Пример:

create_table "messages", :force => true do |t|
  t.boolean :sender_deleted
  t.boolean :receiver_deleted
end

И в модели:

class Message
  def self.delete_message(id)
    m = Message.find(id)
    m.destroy if m.sender_deleted && m.receiver_deleted
  end
end
person Adrian Pacala    schedule 28.02.2011
comment
Вам не кажется, что это просто обходной путь для корректировки плохой модели? Сейчас у моей модели возникает много сомнений... например, мне нужно добавить еще 2 логических значения, чтобы увидеть, прочитали ли уже сообщение пользователи (отправитель и получатель).... - person Joe; 28.02.2011
comment
@ Джо, тебе где-то нужно условие. Вам нужно 4 состояния (для A и B, для A, для B, ни для одного), поэтому вам нужно как минимум 3 состояния, а затем удаление. Два логических значения — это минимум, который вам понадобится, либо в этом решении, либо в другом. - person ANeves thinks SE is evil; 28.02.2011

Вы можете аннулировать удаленную запись с помощью :dependent=>:nullify

has_many :sent_messages, :class_name=> 'Message', :foreign_key=>'source_id', :dependent=>:nullify
has_many :recieved_messages, :class_name=> 'Message', :foreign_key=>'destination_id', :dependent=>:nullify

Вам нужно будет обрабатывать при отображении сообщения, что отправитель/получатель сообщения был удален, поскольку sender_id или destination_id будут нулевыми, но сообщение останется нетронутым.

person Jesse Wolgamott    schedule 28.02.2011
comment
Значит, когда отправитель или получатель удаляет сообщение, другой больше не знает, кто его получил/отправил? Вряд ли это кажется уместным. - person ANeves thinks SE is evil; 28.02.2011
comment
@ANeves Тогда вы действительно не хотите удалять пользователей. Вы хотите мягко удалить их. - person Jesse Wolgamott; 28.02.2011
comment
@ Джесси Уолгамотт Не поймите меня неправильно, но я ничего не хочу. Да, моя точка зрения заключалась в том, что удаление соединения с пользователем удаляет сообщение из списка сообщений пользователя, но также удаляет пользователя из беседы, что, честно говоря, портит сообщение для другого пользователя. - person ANeves thinks SE is evil; 28.02.2011
comment
А если сделать 2 модели? Я говорю о сообщении и message_copy, сообщение будет сообщением с основным текстом, темой, sender_id и Receiver_id, а копия сообщения будет двумя копиями, доставленными отправителю и получателю. Таким образом, они будут иметь независимые копии и выполнять любые действия, которые захотят, не затрагивая другую сторону. Любое предложение о том, как реализовать эту технику, если она умная? Я нашел этот учебник, в котором используется этот метод... Как вы это оцениваете? - person Joe; 02.03.2011
comment
В своем сообщении вы можете хранить всю необходимую информацию, необходимую для сохранения после удаления. Автор Имя, картинка, что угодно. Это будут повторяющиеся данные, но они останутся там навсегда. - person Jesse Wolgamott; 02.03.2011
comment
Я гуглил в течение нескольких дней, message_copy - единственный вариант, который я нашел ... Вы предлагаете сохранить мой подход и добавить логические или любые другие значения, которые мне нужны, непосредственно к модели, о которой я думал в начале в потоке? - person Joe; 02.03.2011
comment
Мне нравится идея хранить сообщение для каждого пользователя. Как электронная почта — у меня как у отправителя есть копия сообщения, а у вас, как у получателя, есть собственное сообщение. Сохраняйте то, что необходимо для каждого сообщения, вместе с идентификатором, чтобы получить дополнительную информацию, если это необходимо (и доступно). - person Jesse Wolgamott; 02.03.2011
comment
Это же моя причина... по логике должны быть разделены, каждый пользователь может делать что хочет со своей копией. Это определенно лучший подход, я буду следовать ему, используя руководство novawave.net/public/rails_messaging_tutorial. html, адаптировав его к моему случаю. Решено, спасибо за предложения - person Joe; 02.03.2011
comment
Меня беспокоит этот учебник... Он использует сообщение (которое хранит author_id и т. д. и т. д., и message_copy каждого из них одному получателю). Что, если автор уничтожит отправленное сообщение (чтобы он удалил сообщение)? В этот момент ассоциация message_copy уничтожается. Так что автор не может уничтожить свои отправленные сообщения... плохо - person Joe; 03.03.2011