Double has_many属性

Rid*_*mer 6 activerecord ruby-on-rails ruby-on-rails-4

我是铁轨的初学者,无法找到适合我的问题的方法.

我有三个模型:对话,参与者,具有以下属性的消息:

会话:

module Messenger
  class Conversation <ActiveRecord::Base

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

    def messages
      self.participants.messages.order(:created_at)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

参与者:

module Messenger

  class Participant <ActiveRecord::Base

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

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

  end
end
Run Code Online (Sandbox Code Playgroud)

信息 :

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
Run Code Online (Sandbox Code Playgroud)

我的麻烦在于我正在尝试制作一个单独的表单来创建一个包含第一条消息的对话.表单如下所示:

= 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'
Run Code Online (Sandbox Code Playgroud)

我已经尝试了很多方法使这个表单变得简单,但我遇到了一些问题,我不知道如何正确使用rails.

我已经尝试过Field_for在我的会话表单中包含一条消息,但由于我的数据库中没有保存任何内容,但似乎我无法将消息链接到未发送的参与者.

所以基本上我希望我的第一个表单,一旦验证,创建一个对话,将当前用户链接到该对话并将消息链接到该第一个用户,但我认为有方法可以使用框架,我不想手动完成.

实现这一目标的正确方法是什么?我甚至在良好的轨道上或者说我改变一些东西或添加一些东西?

编辑:为了使其更容易理解,参与者获得了user_id和conversation_id,这意味着这是一个关系表.我无法调整模型的属性以使其更容易,因为出于安全原因我必须以这种方式保留它.

wjo*_*dan 1

首先,为了让您的表单使用fields_for表单助手接受嵌套属性,您需要accepts_nested_attributes_forConversation模型上指定:

module Messenger
  class Conversation <ActiveRecord::Base

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

    # Required for form helper
    accepts_nested_attributes_for :participants

    [...]
Run Code Online (Sandbox Code Playgroud)

由于您想从同一表单中保存两者Participant以及它,因此您需要在模型上Message添加第二个:accepts_nested_attributes_forParticipant

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
Run Code Online (Sandbox Code Playgroud)

接下来,在您的控制器中,由于这是一个最初Conversation没有任何s 的 new ,因此您需要关联(大概基于),并且还需要与该 new关联:ParticipantbuildParticipantcurrent_userMessageParticipant

def new
  @conversation.participants.build(user: current_user).messages.build
end
Run Code Online (Sandbox Code Playgroud)

最后,form_for @conversation do |f|在您的视图中,指定三个嵌套块、f.fields_for :participants do |p|和中的属性字段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'
Run Code Online (Sandbox Code Playgroud)

旁注:messages中的(错误实现的)方法Conversation应替换为简单的has_many :through关系:

has_many :messages, through: :participants
Run Code Online (Sandbox Code Playgroud)