简体   繁体   English

在Rails中强制has_one关系

[英]Enforce has_one relationship in Rails

I am new to rails and am using the has_one association for the first time. 我是Rails的新手,并且是第一次使用has_one关联。

User Model 用户模型

class User < ActiveRecord::Base
has_one :shop_profile
validates :user_id, presence: true
validates :user_id, uniqueness: true
end

ShopProfile Model ShopProfile模型

class ShopProfile < ActiveRecord::Base
  belongs_to :user
end

However I am still able to make multiple ShopProfiles per user. 但是我仍然能够为每个用户创建多个ShopProfile。 When a user makes a second shop_profile it removes the user_id from the first but there are still two in the database. 当用户创建第二个shop_profile时,它将从第一个shop_profile中删除user_id,但数据库中仍然有两个。

How do you limit the number of ShopProfiles a user can have to 1? 您如何将用户可以拥有的ShopProfiles数量限制为1?

Rails can't do this for you, it's up to you to find the existing record, or create a new one, and it's up to you to ensure that user's aren't creating second ShopProfile records. Rails不能为您做到这一点,它取决于您是查找现有记录还是创建新记录,并且要确保用户不会创建第二个ShopProfile记录。 This shouldn't be a problem, you should be posting back to the correct action ( create vs update ) in the first place, based on the presence of an existing ShopProfile record for the user in question. 这不应该是问题,您应该首先根据存在问题的用户的现有ShopProfile记录将其回发到正确的操作( create vs update )。 You should be raising an error if a user with an existing ShopProfile attempts to post a new one to the create action. 如果具有现有ShopProfile的用户尝试向create操作发布新的错误,则应该引发错误。


Clarification based on your comments: 根据您的评论进行澄清:

The problem here is that you're event letting users hit the creation form for profiles, if they already have a profile. 这里的问题是,如果用户已经拥有个人资料,那么您将通过事件让用户点击个人资料的创建表单。 Once a user has created a profile, if the act of creating a second profile is going to cause an error, users shouldn't be able to get themselves into this state in the first place. 用户创建配置文件后,如果创建第二个配置文件的行为将导致错误,则用户首先不应使自己进入此状态。 Once a user has a profile, you should be linking them to the edit view for that profile, not taking them back to the create view which will just yield an error once they've filled in the form. 用户拥有个人资料后,应将其链接到该个人资料的编辑视图,而不是将他们带回到创建视图,一旦他们填写了表单,这只会产生错误。

That might look something like this: 可能看起来像这样:

<% if @user.shop_profile %>
  <%= link_to 'Edit Profile', [:edit, @user.shop_profile] %>
<% else %>
  <%= link_to 'Create Profile', new_shop_profile_path %>
<% end %>

If a user does somehow hit the "new" action to create a second profile, you should stop them immediately at that point, and refuse to render the creation form. 如果用户确实以某种方式点击了“新”操作来创建第二个配置文件,则应立即将其停止,并拒绝呈现创建表单。 Your new action should probably look something like this: 您的new操作可能应如下所示:

def new
  if @user.shop_profile
    redirect_to edit_shop_profile_path(@user.shop_profile)
  else
    @shop_profile = ShopProfile.new
  end
end

The alternative is that you need to provide users some way forward if they ask to create a new profile when they have an existing one. 另一种选择是,如果用户要求创建新的配置文件,则需要为他们提供一些前进的方式。 This might be a checkbox on your "create" form that lets them opt to overwrite their existing profile. 这可能是“创建”表单上的复选框,使他们可以选择覆盖其现有的配置文件。 The point is, you need to give them some way of proceeding through the various flows of your application, or else your application is basically broken. 关键是,您需要给他们一些方法来处理您的应用程序的各种流程,否则您的应用程序基本上就被破坏了。 You should never back a user into a place where they're filling in a form with no actual way of successfully submitting it. 您永远不应将用户带回他们正在填写表单的地方,而没有成功提交表单的实际方法。

I think the best solution is to create profile after the registration so in your user model put this code 我认为最好的解决方案是在注册后创建配置文件,因此在您的用户模型中放置此代码

  has_one :profile, dependent: :destroy
  after_create :create_profile

  private

  def create_profile
    Profile.create(user: self)
  end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM