正确定义一个真正一对一的约束

时间:2018-08-02 15:00:10

标签: ruby-on-rails ruby relational-database

我们的系统中存在一对一的关系。

让我们使用用户->地址的典型示例:

join on

在这种情况下,用户具有一个class User < ApplicationRecord belongs_to :address end class Address < ApplicationRecord has_one :user end 字段,该地址没有任何引用该用户的数据库字段。

现在我继续创建用户和地址,一切都很好:

address_id

但是当我与现有用户创建其他地址时,我将得到2个地址。

user = User.create(address: Address.create)

通常没什么大不了的,但出于报告目的,可能会出错。

所以我的问题是:我如何确保只有一个用户与一个地址相关联,反之亦然?

2 个答案:

答案 0 :(得分:0)

要真正执行此操作,可以在users.address_id列上定义一个唯一索引。

总体而言,我建议您不要使用Address.create:如果您使用address.create_user,Active Record会做得更好(尽管仍然不完美,尤其是面对并发请求)为您控制一切。

(当然,从地址创建用户没有多大的意义……如果您沿着那条路走,我会考虑翻转关系以使该地址更隶属于该用户。要点是通过has_one进行操作会为您带来更多has_one意识的行为。)

答案 1 :(得分:0)

我相信您遇到的问题可能与控制器有关,而不是与模型约束有关。

您的User模型可以accept_nested_attributes_for :address

您的新操作和修改操作如下所示:

def new
  @user = User.new
  @user.build_address
end

def edit
  @user = User.find(params[:id])
  @user.build_address if @user.address.blank?
end

您的用户表单可能类似于:

<%= fields_for :address do |address_form| %>
  <%= address_form.text_field :street_line_one %>
  <%= address_form.text_field :street_line_two %>
  <%= address_form.text_field :city %>
  <%= address_form.text_field :postal_code %>
  <%= address_form.text_field :region_name %>
<% end %>

这应确保在创建新用户时创建新对象,并应确保在更新具有现有地址的用户时更新现有地址。

如果仍然无法按预期运行,则必须添加更多细节,例如控制器和表单的外观,才能确切知道如何解决问题。