Double has_many属性

时间:2017-01-24 10:20:39

标签: ruby-on-rails ruby-on-rails-4 activerecord

我是初学者,很难找到解决问题的方法。

我有三种模式:会话,参与者,具有以下属性的消息:

对话:

module Messenger
  class Conversation <ActiveRecord::Base

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

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

参与者:

module Messenger

  class Participant <ActiveRecord::Base

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

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

  end
end

消息:

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

我的麻烦在于我正在尝试使用单个表单创建一个包含第一条消息的对话。表格如下:

= 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'

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

我已尝试使用Field_for在我的对话表单中添加一条消息,但由于我的数据库中没有保存任何内容,但似乎我无法将消息链接到未存在的参与者。

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

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

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

3 个答案:

答案 0 :(得分:2)

消息需要belong_to直接对话,因为您需要消除参与者何时有多个对话的歧义。

因此,您可以使用

在控制器中构建对话的默认消息
@conversation.messages.build(participant: @conversation.participants.first)

这非常罗嗦,所以你可以添加一些模型方法来减少对

的控制器调用
@conversation.build_default_message

在这种情况下,您想要创建一个Conversation,但它也需要创建一个带有用户输入的Message。因此Conversation需要代表Message接受属性。您可以使用accepts_nested_attributes_for

执行此操作
class Conversation
  accepts_nested_attributes_for :messages
end

这将允许您使用

创建一个包含一个或多个关联消息的对话
Conversation.create(
  ..., 
  messages_attributes: [
    { participant_id: 1, content: 'question' } 
  ]
)

答案 1 :(得分:1)

首先,为了让您的表单使用fields_for表单帮助器接受嵌套属性,您需要在NoFile模型上指定accepts_nested_attributes_for:< / p>

Maybe File

由于您要同时保存同一表单中的Conversation及其module Messenger class Conversation <ActiveRecord::Base has_many :participants, :class_name => 'Messenger::Participant' # Required for form helper accepts_nested_attributes_for :participants [...] ,因此您需要在Participant模型上添加第二个Message:< / p>

accepts_nested_attributes_for

下一步,在您的控制器中,由于这是一个最初没有Participant的新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 ,您需要build关联Conversation(可能基于Participant),以及此新Participant的关联current_user

Message
在您的视图中

最后,在三个嵌套块中指定属性字段Participantdef new @conversation.participants.build(user: current_user).messages.build end 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' 方法应替换为简单的has_many :through关系:

messages

答案 2 :(得分:0)

首先,我认为,你在这种方法上有错误:

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

Conversation has_many :participants

以来

self.participants将返回一个数组,而不是一个Participant活动记录对象。因此,您无法直接在阵列上调用messages。您需要迭代该数组并在每个对象上调用messages

使用嵌套表单和fields_for方法以及accepts_nested_attributes_for(您可以找到如何从SO或文档中编写这些内容)并发布代码和错误。然后有人可能会帮助你。

使用fields_for

由于您无法将邮件直接链接到Conversation,并且您需要一个邮件字段,因此您需要将@message链接到任何参与者。您可以为Participant或第一位用户构建current_userUser.first@conversation,然后为此@message构建Participant