Rails嵌套属性和has_many:通过不显示fields_for的关联

时间:2015-01-18 06:11:34

标签: devise nested-forms nested-attributes

以下是我的模特:

class Company < ActiveRecord::Base

  has_many :roles, :dependent => :destroy, :inverse_of => :user
  has_many :users, :through => :roles
  validates :name, presence: true

end

class User < ActiveRecord::Base

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :roles, :dependent => :destroy, :inverse_of => :user
  has_many :companies, :through => :roles
  accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true

end

class Role < ActiveRecord::Base

  belongs_to :user, :inverse_of => :roles
  belongs_to :company, :inverse_of => :roles

  #accepts_nested_attributes_for :companies, :limit => 1, :allow_destroy => true
  accepts_nested_attributes_for :company

end

这里的想法是公司是独一无二的,用户可以通过角色与多家公司相关联。我在用户模型上设置了用于身份验证和注册的设计。这工作正常,我可以注册成为新用户。

我想将公司名称添加到注册过程中。我正在尝试嵌套表单:

<%= form_for(resource, :html => {:class => "form-signin" }, as: resource_name, url: registration_path(resource_name)) do |f| %>
    <%= render partial: "shared/flash" %>
    <%= devise_error_messages! %>
    <h1 class="form-signin-heading text-muted">Register</h1>
    <%= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true %>
    <%= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off" %>
    <%= f.password_field :password_confirmation, class: "form-control", placeholder: "Password Confirmation", autocomplete: "off" %>

    <%= f.fields_for :roles do |r| %>
    <%= r.fields_for :company do |c| %>
          <%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
    <% end %>
    <% end %>
    <button class="btn btn-lg btn-primary btn-block" type="submit">
        Register
    </button>
<% end %>

我找到了一些其他的SA答案,指出需要通过accepts_nested_attributes_for通过关联以及一些单/复数问题来深入研究has_many。修复了我的表单加载后没有错误,除了fields_for块为空。

现在我承认我的模型可能是这里的问题。我已经复制了几年前我工作的应用程序的代码,所以我已经忘记了为什么我这样做了。

在一天结束时,我想在用户注册时创建公司和角色。我计划将角色的创建添加到公司控制器,但我需要至少先创建公司。

更新

我做了一些挖掘并更新了我的表格:

    <% company = resource.companies.build %>
    <%= f.fields_for :company, company do |c| %>
          <%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
    <% end %>

我意识到我的Devise控制器没有构建嵌套的Company资源。我想远离定制的Devise控制器。我的表单提交并且我的用户已创建,但我仍然遗漏了这里的内容,因为公司和角色没有得到保存。

1 个答案:

答案 0 :(得分:1)

经过一番挖掘和实验,我就是这样解决的:

<强>模型

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :roles, :dependent => :destroy, :inverse_of => :user
  has_many :companies, :through => :roles
  accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true

end

class Role < ActiveRecord::Base
  belongs_to :user, :inverse_of => :roles
  belongs_to :company, :inverse_of => :roles
  accepts_nested_attributes_for :company
end

class Company < ActiveRecord::Base
  has_many :roles, :dependent => :destroy, :inverse_of => :user
  has_many :users, :through => :roles
  validates :name, presence: true
end

自定义设计注册控制器

class RegistrationsController < Devise::RegistrationsController

    # GET /resource/sign_up
  def new
    build_resource({})
    @role = resource.roles.build(role: "owner", active: 1, default_role: 1)
    @company = @role.build_company
    set_minimum_password_length
    yield resource if block_given?
    respond_with self.resource
  end

  protected

  def sign_up_params
      params.require(:user).permit(:email, :password, :password_confirmation, roles_attributes: [ company_attributes: [ :id, :name ] ] )
  end

end

<强> HTML

<%= form_for(resource, :html => {:class => "form-signin" }, as: resource_name, url: registration_path(resource_name)) do |f| %>
    <%= render partial: "shared/flash" %>
    <%= devise_error_messages! %>
    <h1 class="form-signin-heading text-muted">Register</h1>
    <%= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true %>
    <%= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off" %>
    <%= f.password_field :password_confirmation, class: "form-control", placeholder: "Password Confirmation", autocomplete: "off" %>

    <%= f.fields_for :roles, resource.roles.build do |r| %>
    <%= r.fields_for :company, resource.roles.build.build_company do |c| %>
          <%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
    <% end %>
    <% end %>

    <button class="btn btn-lg btn-primary btn-block" type="submit">
        Register
    </button>
<% end %>

我认为我的模特和协会搞砸了。现在form_for正在起作用。

我将发布另一个单独的问题,但是当我仍然无法弄清楚是:

  • 为什么我在控制器中设置的@role和@company在视图HTML中工作?
  • 如何设置其他角色属性?我在构建阶段尝试了控制器和视图,但它没有。