2017-01-24 12 views
7

Tôi là người mới bắt đầu trong đường ray và gặp khó khăn trong việc tìm kiếm một cách phù hợp với vấn đề của tôi.Đôi thuộc tính has_many

Tôi có ba mô hình: Đối thoại, người tham gia, các thông điệp đó có các thuộc tính sau:

thoại:

module Messenger 
    class Conversation <ActiveRecord::Base 

    has_many :participants, :class_name => 'Messenger::Participant' 

    def messages 
     self.participants.messages.order(:created_at) 
    end 
    end 
end 

tham gia:

module Messenger 

    class Participant <ActiveRecord::Base 

    has_many :messages, :class_name => 'Messenger::Message' 

    belongs_to :conversation, :class_name => 'Messenger::Conversation' 

    end 
end 

nhắn:

module Messenger 

    class Message <ActiveRecord::Base 

    default_scope {order(:created_at)} 
    default_scope {where(deleted: false)} 

    belongs_to :participant, :class_name => 'Messenger::Participant' 

    end 
end 

Vấn đề của tôi là tôi đang cố tạo một biểu mẫu duy nhất để tạo một cuộc hội thoại với một thông điệp đầu tiên trong đó. Biểu mẫu có dạng như sau:

= form_for @conversation, url: messenger.conversations_create_path do |f| 
    .row 
    .col-md-12.no-padding 
     .whitebg.padding15 
     .form-group.user-info-block.required 
      = f.label :title, t('trad'), class: 'control-label' 
      = f.text_field :title, class: 'form-control' 

     .form-group.user-info-block.required 
      = f.label :model, t('trad'), class: 'control-label' 
      = f.text_field :model, class: 'form-control' 

     .form-group.user-info-block.required 
      = f.label :model_id, t('trad'), class: 'control-label' 
      = f.text_field :model_id, class: 'form-control' 

     = fields_for @message, @conversation.participants.message do |m| 
      = m.label :content, t('trad'), class: 'control-label' 
      = m.text_area :content, class:'form-control' 

    .user-info-block.action-buttons 
    = f.submit t('trad'), :class => 'btn btn-primary pull-right' 

Tôi đã thử nhiều cách để làm cho biểu mẫu này đơn giản nhưng tôi đã gặp phải một số sự cố mà tôi không biết cách khắc phục bằng cách sử dụng đúng cách.

Tôi đã thử sử dụng Field_for để bao gồm thư trong biểu mẫu cuộc trò chuyện, nhưng vì tôi không có gì được lưu trong cơ sở dữ liệu của mình, có vẻ như tôi không thể liên kết thư với người tham gia chưa có. Vì vậy, về cơ bản tôi muốn biểu mẫu đầu tiên của mình, khi được xác thực, để tạo cuộc trò chuyện, liên kết người dùng hiện tại với cuộc trò chuyện đó và liên kết thông báo với người dùng đầu tiên đó, nhưng tôi cho rằng có nhiều cách để làm điều đó với khung công tác và không muốn làm điều đó theo cách thủ công.

Cách thích hợp để làm theo để đạt được điều đó là gì? Tôi thậm chí trên đường đua tốt hay shoould tôi thay đổi một cái gì đó hoặc thêm một cái gì đó?

Chỉnh sửa: để làm cho người dùng dễ hiểu hơn, người tham gia có user_id và cuộc trò chuyện_id, có nghĩa đây là bảng quan hệ. Tôi không thể thích nghi với các thuộc tính của các mô hình của tôi để làm cho nó dễ dàng hơn vì tôi phải giữ nó theo cách đó vì lý do bảo mật.

+0

bạn có thể muốn xem xét has_many thông qua hiệp hội cho các tin nhắn trong Đối thoại thay vì phương pháp cán tay của bạn. – engineerDave

Trả lời

1

Đầu tiên, để cho hình thức của mình để chấp nhận các thuộc tính lồng nhau bằng cách sử dụng helper fields_for biểu mẫu, bạn cần phải xác định accepts_nested_attributes_for trên mô hình Conversation của bạn:

module Messenger 
    class Conversation <ActiveRecord::Base 

    has_many :participants, :class_name => 'Messenger::Participant' 

    # Required for form helper 
    accepts_nested_attributes_for :participants 

    [...] 

Vì bạn muốn tiết kiệm một cả Participant cũng như Message của nó từ hình thức tương tự, bạn cần phải thêm một giây accepts_nested_attributes_for trên mô hình Participant của bạn:

module Messenger 

    class Participant <ActiveRecord::Base 

    has_many :messages, :class_name => 'Messenger::Message' 

    # Required for form helper 
    accepts_nested_attributes_for :messages 

    belongs_to :conversation, :class_name => 'Messenger::Conversation' 

    end 
end 

Tiếp, trong điều khiển của bạn, vì đây là một mới Conversation mà không có bất kỳ Participant s lúc đầu, bạn cần phải build một liên Participant (có lẽ dựa trên current_user), và cũng là một liên Message cho mới này Participant:

def new 
    @conversation.participants.build(user: current_user).messages.build 
end 

Cuối cùng theo quan điểm của bạn, xác định các lĩnh vực thuộc tính trong ba khối lồng nhau, , f.fields_for :participants do |p|, và p.fields_for :messages do |m|:

= form_for @conversation, url: messenger.conversations_create_path do |f| 
    [...] 
    = f.fields_for :participants do |p| 
    = p.fields_for :messages do |m| 
     = m.label :content, t('trad'), class: 'control-label' 
     = m.text_area :content, class:'form-control' 

    .user-info-block.action-buttons 
    = f.submit t('trad'), :class => 'btn btn-primary pull-right' 

Side lưu ý: (thực hiện không chính xác) messages phương pháp trong Conversation nên được thay thế bởi một has_many :through mối quan hệ đơn giản:

has_many :messages, through: :participants 
+0

Vâng, Cảm ơn bạn hàng triệu lần, đó là kết quả tôi đang tìm kiếm và thực sự là từ khóa thông qua là một cải tiến lớn cho mã của tôi. Làm việc hoàn hảo, được chấp nhận! – RiddlerNewComer

2

Tin nhắn cần phải belong_to Cuộc trò chuyện trực tiếp, vì bạn cần phải định hướng khi người tham gia có nhiều cuộc trò chuyện.

Vì vậy, khi làm điều đó, bạn có thể xây dựng thông điệp mặc định của cuộc trò chuyện trong bộ điều khiển sử dụng

@conversation.messages.build(participant: @conversation.participants.first) 

Đó là khá dài dòng, vì vậy bạn có thể thêm một vài phương pháp mô hình để giảm các cuộc gọi điều khiển để

@conversation.build_default_message 

Trong trường hợp này, bạn muốn tạo Cuộc hội thoại, nhưng cũng cần phải tạo Tin nhắn với thông tin nhập của người dùng. Vì vậy, Hội thoại cần chấp nhận các thuộc tính thay mặt cho Thư.Bạn có thể làm điều đó bằng accepts_nested_attributes_for

class Conversation 
    accepts_nested_attributes_for :messages 
end 

Điều này sẽ cho phép bạn tạo một Đối thoại với 1 hoặc tin nhắn có liên quan hơn bằng cách sử

Conversation.create(
    ..., 
    messages_attributes: [ 
    { participant_id: 1, content: 'question' } 
    ] 
) 
+0

Chúng tôi đã xác định mô hình của chúng tôi như thế này và không thể liên kết trực tiếp thư trong hội nghị vì lý do bảo mật, đây là lý do tôi cần giữ mô hình như vậy – RiddlerNewComer

0

Trước hết, tôi nghĩ rằng, bạn có sai lầm trong phương pháp này:

def messages 
    self.participants.messages.order(:created_at) 
end 

từ Conversationhas_many :participants:

self.participants sẽ trả về một mảng, không phải là một đối tượng bản ghi hoạt động Participant. Vì vậy, bạn không thể gọi trực tiếp messages trên một mảng. Bạn cần phải lặp lại mảng đó và gọi messages trên mỗi đối tượng.

Sử dụng biểu mẫu lồng nhau và phương thức fields_foraccepts_nested_attributes_for (bạn có thể tìm cách viết chúng từ SO hoặc tài liệu) và đăng mã và lỗi những gì bạn có. Sau đó, ai đó có thể giúp bạn.

Và để sử dụng fields_for:

Vì bạn không thể liên kết nhắn trực tiếp đến một Conversation và bạn cần một trường tin nhắn, bạn cần liên kết một @message cho bất kỳ người tham gia. bạn có thể tạo một số Participant từ current_user hoặc người dùng đầu tiên, ví dụ: User.first cho số @conversation và sau đó tạo @message cho số Participant này.

Các vấn đề liên quan