使用form_for与“成为”失去了儿童关联

时间:2016-01-15 21:38:09

标签: ruby-on-rails associations

当构建一个处理STI的表单时,如果我使用becomes将对象转换为其父类,我将失去使用嵌套字段的能力。

我有两个型号

class Login < ActiveRecord::Base
  belongs_to :user
end

class User < ActiveRecord::Base
  has_one :login

  accepts_nested_attributes_for :login
end

我还有一些User的子类。

class Consumer < User
end

class Admin < User
end

class Agent < User
end

最初我遇到路由问题,因为Rails会假设我想要一个特定于当前类而不是父类的路由,所以我使用@user.becomes(User),这显然是处理它的方法。在大多数情况下,它工作正常,但这会导致@user.login消失。

控制器

class Admin::UsersController < AdminController
  load_and_authorize_resource
  before_filter :authenticate_user!

  def index
    render 'index'
  end

  def new
    @user = User.new
    @user.build_login
    render 'new'
  end

  def create
    @user = User.new(user_params)

    if @user.save
      flash[:notice] = "Account confirmation instructions sent to #{@user.login.email}"
      redirect_to new_user_path
    else
      flash.now[:error] = @user.errors.full_messages.to_sentence
      # At this point, I can confirm that @user.login still exists...
      render 'new'
    end
  end

  private
    def user_params
      params.require(:user).permit(
        :type,
        :dealership_id,
        login_attributes: [
          :email
        ])
    end

end

这是最相关的表单视图位

<%= simple_form_for(@user.becomes(User), html: {class: "user-form"}) do |f| %>

  <%= f.simple_fields_for :login do |l| %>
    <div class="field">
      <%= l.label :email %><br />
      <%= l.email_field :email %>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :type %>
    <%= f.select :type, options_for_select(current_user.types_can_create), include_blank: "- Select -", class: "form-control", id: "select_type" %>
  </div>

  <div class="actions">
    <%= f.submit "Register" %>
  </div>
<% end %>

:email的文字字段未显示,因为@user.login现在是nil。使用becomes时,这是预期的行为吗?

2 个答案:

答案 0 :(得分:1)

之前只使用了becomes,我只能证明我的经验 - 无论何时使用它,它实际上都会调用该类的新实例。

我不确定具体细节,但最重要的是,我猜测你的@user.becomes(User)会覆盖@user.build_login ......

  

返回具有当前记录属性的指定klass的实例。

-

在您的情况下,我会明确设置路径(因为您正在使用User):

<%= simple_form_for @user, url: user_path, method: :post html: {class: "user-form"} do |f| %>

答案 1 :(得分:0)

在Rails 5中,可以通过以下方式解决

<%= form_with scope: :user,
              model: @user,
              url: @user.id ? user_path(user) : users_path,
              local: true do |f| %>
  ...
  ...
<% end %>

前面的代码指示FormBuilder使用@user属性填充字段,但是还指示它提交到主路由(而不是继承的路由),并使用scope:对其进行指示。使用User类名而不是子类名来命名字段。