【问题标题】:Rails - Autocreate an associated modelRails - 自动创建关联模型
【发布时间】:2015-10-20 11:15:50
【问题描述】:

我是 Rails 新手,我正在创建一个简单的应用程序,它的客户端带有 addersses。在得到栈溢出社区的一些建议和意见后,我decided to save addresses as a seperate model

我现在正尝试在我的应用程序中实现此功能,但在从“新客户”表单中获取正确保存地址时遇到问题。到目前为止,这是我的代码:

class Address < ActiveRecord::Base
    belongs_to :client
end

class Client < ActiveRecord::Base
    has_one :address
    before_create :build_address, unless: Proc.new { |client| client.address }
end



<%= form_for(@client) do |f| %>
  <% if @client.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@client.errors.count, "error") %> prohibited this client from being saved:</h2>

      <ul>
      <% @client.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :phone_number %><br>
    <%= f.text_field :phone_number %>
  </div>

  <%= f.fields_for :address do |a| %>
    <div class="field">
      <%= a.label :house_number %><br>
      <%= a.number_field :house_number %>
    </div>
    <div class="field">
      <%= a.label :house_name %><br>
      <%= a.text_field :house_name %>
    </div>
    <div class="field">
      <%= a.label :post_code %><br>
      <%= a.text_field :post_code %>
    </div>
  <% end %>

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

<% end %>

这样,客户端创建成功,但地址记录创建为空字段。没有错误。

任何帮助将不胜感激。

谢谢

【问题讨论】:

  • 你有accepts_nested_attributes_for :address吗? params.require(:client) 你有什么?

标签: ruby-on-rails ruby model associations


【解决方案1】:

首先 - ActiveModel 回调不会引起悲伤的情况很少。通常将逻辑放入模型中是一件好事——但让回调在你需要的时候运行而不是在不相关的测试中运行几乎是不可能的。

在这种情况下,您只需构建地址,以便在新操作中预先填充表单输入。没有其他理由让您的所有 Client 实例一直有一个空地址记录捎带它们。

所以我们会这样做:

class Client < ActiveRecord::Base
  has_one :address
  accepts_nested_attributes_for :address
end

class ClientController < ApplicationController
  def new 
    @client = Client.new
    @client.build_address
  end

  def create
    @client = Client.create(client_params)
    # ...
  end

  def client_params
    params.require(:client)
          .permit(
             :name, :phone_number, 
             address_attributes: [:house_number, :house_name]
          )
  end
end

【讨论】:

  • 感谢您的回复。这给了我一个错误:nil:NilClass 的未定义方法 `build_address'
  • 原来是 client.build_address 而不是 @client.address.build_address。再次感谢 max
  • 当您在记录实际插入数据库之前(但在验证之后)调用.save 时,也会运行before_create。如果您要使用回调,它将是after_initializeapi.rubyonrails.org/classes/ActiveRecord/Callbacks.html
【解决方案2】:

你需要accepts_nested_attributes_for:

#app/models/client.rb
class Client < ActiveRecord::Base
    has_one :address
    accepts_nested_attributes_for :address
    before_create :build_address, unless: Proc.new { |client| client.address }
end

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

#app/controllers/clients_controller.rb
class ClientsController < ApplicationController
   def new
      @client = Client.new
      @client.build_address
   end
end

这应该适合你。

【讨论】:

  • build_address 不会运行两次?
  • 否,有两个原因。 1) build_address 仅在new(不是create)中显式调用,2) after_create 回调有一个条件,如果地址存在则阻止构建
猜你喜欢
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多