← Back to Upcase

Creating an associated model during model creation

(Neil Edwards) #1


I have a User model and I have a Company model. A Company has many Users. A User has one Company. A User must always have an associated Company.

There are two ways a User can be created:

  • Directly via the ‘sign up’ link on the website
  • Via an invitation sent from another user.

If the user signs up directly from the website then they are deemed to be the first user for a new Company.

At the moment I’m taking in the name of the Company as part of the Sign Up form and I’m using the before_create callback in the User model to do something like:

  before_create :create_company

  def create_company
    unless self.company
      self.company = Company.create!(name: company_name)

When a user is invited then devise_invitable creates a new User model and at that point I can set the company attribute of the new invitee to be the same of the inviter…

Finally, the question, is the before_create callback a good place for something like creating a required association. Is there some better way of doing it? For some reason I don’t like callbacks, I especially dont’ like the idea of a callback that creates a new model, but I’m unsure of a better way.

tl;dr Is it good practise to create a new model in the before_create callback of a different model?

Thanks for reading, and for any advice.

(Erik Guzman) #2

One technique you can go for is to use a wrapper class that constructs the user, company and sets up any other associations instead of using call backs.

(Neil Edwards) #3

OK thanks, so maybe a UserFactory kind-of-thing which sets up the User with it’s associations and I’d do a UserFactory.new(company) or something.

OK thanks, that does seem cleaner than requiring the User to know it should create a Company association, I’ll keep that in mind and have a play.

(Pedro Moreira) #4

I think erikguzman is right. I was facing the same problem with creating an Account object and a User object and decided to go with a Form Object, as detailed in this post.