Rails嵌套属性创建有很多通过关联,但想要在其上设置更多数据

时间:2015-10-01 18:05:14

标签: ruby-on-rails

我设置了三个模型,如下所示(为简洁起见不完整):

class Client < ActiveRecord::Base
  has_many :roles
  has_many :cases, through: :roles
end

class Role < ActiveRecord::Base
  belongs_to :client
  belongs_to :case
end

class Case < ActiveRecord::Base
  has_many :roles
  has_many :clients, through: :roles

  accepts_nested_attributes_for :roles, :clients
end

这是一个简单的has_many through关联。我已将模型设置为接受适当关联的嵌套属性,并在我的控制器中正确地允许参数。我将下面的请求正文JSON发送到POST /cases,这会触及此方法:

def create
  @case = Case.new(case_params)

  if @case.save
    render json: @case, root: 'case', status: :created, location: @case, serializer: CaseShowSerializer
  else
    render json: @case.errors, status: :unprocessable_entity
  end
end

JSON:

{
    "case": {
        "state": "CA",
        "clients_attributes": [
            {
                "first_name": "John",
                "last_name": "Doe",
                "email": "johndoe@gmail.com"
            }
        ]
    }
}

创建案例并创建嵌套客户端数组。 Rails自动为JSON数组中的每个Role创建Client条记录。但是,它仅设置case_idclient_id(将两者关联起来)。我 想要在其创建的Role模型上设置其他字段。

如何做到这一点?

编辑:

以下两个答案(2015年10月1日,太平洋标准时间下午12:50)将无效。使用这些答案的逻辑,客户端不能拥有多个角色(在模型中需要并明确定义)。

示例:

角色无法嵌套在案例中 -

{
  "case": {
    "name": "test",
    "roles_attributes": [
      {
        "type": "Type 1",
        "client_attributes": {
          "name": "Client 1"
        }
      },
      {
        "type": "Type 2",
        "client_attributes": {
          "name": "Client 1"
        }
      }
    ]
  }
}

上面的JSON将创建两次 SAME 客户端。客户名称为&#34;客户1&#34;有两个角色,其中一个角色类型是&#34;类型1&#34;另一个是&#34;类型2&#34;。答案建议的上面的代码段将创建两个客户端和两个角色。它应该创建一个客户端(因为它是同一个客户端,但该客户端有多个角色)。

2 个答案:

答案 0 :(得分:0)

不是发布SELECT * FROM (SELECT t1.a t1_a , t1.b t1_b , t1.c t1_c , t2.a t2_a , t2.b t2_b , t2.c t2_c FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.b = '000000' AND LENGTH(t1.a) > '5' AND t1.c <> 'Y') a LEFT JOIN (SELECT t1.a t1_a , t1.b t1_b , t1.c t1_c , t3.a t3_a , t3.b t3_b , '0' + LEFT(t3.c, 5) t3_c , LEFT(t3.c, 5) AS testMe FROM t1 LEFT JOIN t3 ON t1.a = '0' + LEFT(t3.c, 5)) b ON a.t1_a = c.t3_c; ,而是为clients_attributes发布每个角色所需的数据。

roles_attributes中的每个role都可以包含嵌套的roles_attributes对象。

执行此操作时,您可能无法保存引用现有client的新角色。检查the answer to this question是否有解决方法。

答案 1 :(得分:0)

我之前能够做到这一点的唯一方法是定义各种模型&#39;属性因为它们是必需的。 I wrote an answer about it一会儿。

你的方式比我的更简洁(和更好)。但是,您应该能够像我一样通过它传递您需要的数据:

{
    "case": {
        "state": "CA",
        "roles_attributes": [
           "name": "Admin",
           "client_attributes": [
               {
                   "first_name": "John",
                   "last_name": "Doe",
                   "email": "johndoe@gmail.com"
               }
           ]
        ]
    }
}

如果您不想使用JSON,并且必须从HTML表单中填充数据等,那么您将使用以下内容:

#app/controllers/cases_controller.rb
class CasesController < ApplicationController
   def new
      @case = Case.new
      @case.roles.build.build_client
   end

   def create
      @case = Case.new case_params
      @case.save
   end

   private

   def cases_params
      params.require(:case).permit(:state, roles_attributes: [:name, clients_attributes:[:first_name, :last_name, :email])
   end
end

您必须使用适当的模型嵌套属性进行备份:

#app/models/role.rb
class Role < ActiveRecord::Base
  belongs_to :client
  belongs_to :case

  accepts_nested_attributes_for :client
end

class Case < ActiveRecord::Base
  has_many :roles
  has_many :clients, through: :roles

  accepts_nested_attributes_for :roles
end

这将允许您使用fields_for帮助程序:

#app/views/cases/new.html.erb
<%= form_for @case do |f| %>
   <%= f.text_field :state %>
   <%= f.fields_for :roles do |role| %>
      <%= role.text_field :name %>
      <%= role.fields_for :client do |client| %>
         <%= client.text_field :first_name %>
         <%= client.text_field :last_name %>
         <%= client.email_field :email %>
      <% end %>
   <% end %>
   <%= f.submit %>
<% end %>