嵌套表单与has_one:through

时间:2015-10-25 03:55:39

标签: ruby-on-rails

我在实现具有has_one :through关联的嵌套表单时遇到了一些麻烦。

模型

# model: member.rb

belongs_to :user
has_one :academic

# model: user.rb

has_one :member
has_one :academic, through: :member

accepts_nested_attributes_for :member, reject_if: :all_blank 
accepts_nested_attributes_for :academic, reject_if: :all_blank

# model: academic.rb

belongs_to :member
belongs_to :user 

控制器

# users_controller.rb

def new
  @user = User.new
  @user.build_member
  @user.build_academic  
end

我也尝试过:

@user.member.build_academic

视图

# new.html.erb

<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |ff| %>

  <%= ff.text_field :email %>

# member belongs to user so I can call a fields_for
<% ff.fields_for :member do |f| %>

  <%= f.text_field :name %>

# this part is not shown. What is wrong with my association?
<% f.fields_for :academic do |a| %>

  <%= a.text_field :major %>

<% end %>
 <% end %>
  <% end %>

我已经看了一下Rails文档。第一个fields_for显示在页面中(:member),但第二个:academichas_one :through关联,未显示在页面中。< / p>

任何帮助将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:2)

如果您想通过关系构建数据,则必须在构建时传递相关数据:

#app/models/member.rb
class Member < ActiveRecord::Base
   belongs_to :user
   has_one :academic

   accepts_nested_attributes_for :academic
end

#app/models/user.rb
class User < ActiveRecord::Base
   has_one :member
   has_one :academic, through: :member

   accepts_nested_attributes_for :member
end

#app/models/academic.rb
class Academic < ActiveRecord::Base
   belongs_to :member
   belongs_to :user
end

这将允许您执行以下操作:

#app/controllers/members_controller.rb
class MembersController < ApplicationController
   def new
      @member = Member.new
      @member.build_member.build_academic
   end

   def create
      @member = Member.new member_params
      @member.save
   end

   private

   def member_params
      params.require(:member).permit(:x, :y, :z, academic_attributes: [:some, :attributes, member_attributes:[...]])
   end
end

这将允许以下内容:

#app/views/users/new.html.erb
<%= form_for @user do |f| %>
   <%= f.fields_for :member do |m| %>
      <%= f.text_field :name %>
      ...
      <%= m.fields_for :academic do |a| %>
           <% a.text_field :name %>
           ...
      <% end %> 
   <% end %>
   <%= f.submit %>
<% end %>

这适用于构建新的member对象,以及来自academic的新user对象。虽然不是严格要求的,但看起来它可能会以某种形式对你有所帮助。

协会

如果你想做你所要求的(IE build_memberbuild_academic专属),你需要摆脱has_one :through关系...

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :memberships
   has_many :academics, through: :memberships
end

#app/models/membership.rb
class Membership < ActiveRecord::Base
   belongs_to :user
   belongs_to :academic
end

#app/models/academic.rb
class Academic < ActiveRecord::Base
   has_many :memberships
   has_many :users, through: :memberships
end

问题是你基本上是在尝试为直接关联(member建立间接关系(academic)。

如果您想要独占构建, 可以使它们与您的主模型直接关联。以上应该允许您执行以下操作:

#app/controllers/users_controller.rb
class UsersController < ApplicationController
   def new 
       @user = User.new
       @user.members.build.academics.build
   end
end

就像我的顶级示例一样,这将通过您的表单传递嵌套数据 - 如果您想完全独占,请执行此操作:

#app/models/user.rb
class User < ActiveRecord::Base
   has_one :member
   has_one :academic
   has_and_belongs_to_many :academics
end

#app/models/member.rb
class Member < ActiveRecord::Base
   belongs_to :user
end

#app/models/academic.rb
class Academic < ActiveRecord::Base
   belongs_to :user
   has_and_belongs_to_many :users
end

这将允许以下内容:

#app/controllers/users_controller.rb
class UsersController < ApplicationController
   def new
      @user = User.new
      @user.build_member
      @user.build_academic
   end

   def create
      @user = User.new user_params
      @user.save
   end

   private

   def user_params
      params.require(:user).permit(:user, :params, member_attributes: [], academic_attributes:[])
   end
end

答案 1 :(得分:1)

为了将来参考或任何有相同问题的人,我找到了解决此问题的方法,以防您有相同的结构。

我可以通过转到表单前的view并写下:

来解决这个问题
<% resource.member.build_academic %>

在我的情况下,resource是由devise设置的User,用于身份验证的Rails gem。

并且您不需要引用模型中的任何:through或任何内容。

这不是最有效的方式,但我还没有找到任何其他解决方案。希望它有所帮助。