0
votes

I am new to rails and am using the has_one association for the first time.

User Model

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

ShopProfile Model

class ShopProfile < ActiveRecord::Base
  belongs_to :user
end

However I am still able to make multiple ShopProfiles per user. When a user makes a second shop_profile it removes the user_id from the first but there are still two in the database.

How do you limit the number of ShopProfiles a user can have to 1?

2
Thanks for the reply, I have added the validatiosns as shown above but I do not get normal error messages such as with other validations. I get a full error page saying "Failed to remove the existing associated shop_profile. The record failed to save after its foreign key was set to nil." I would like to just have an error message show in a flash, how can I do this?Cu1ture

2 Answers

2
votes

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. 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. You should be raising an error if a user with an existing ShopProfile attempts to post a new one to the create action.


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:

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.

1
votes

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