0

I want to modify my application in a way that on the signup page, user specifies his company. If the company with a particular name already exists, the newly created user gets assigned to the company (by company_id), if not, the company gets created in the company table, and the user gets the company_id assigned in the users table record.

I've managed to make the app create the user, and create a correct company in another table, But I can't figure out how to make it so that if the company already exists, user just gets the existing company id.

Now on to what I've done so far. One user belongs to one company, and one company has many users.


The user table has a new column named company_id

The Company table has company_name

As for models:

User Model (... truncates unnecesary code)

class User < ActiveRecord::Base
...
  belongs_to :company
  accepts_nested_attributes_for :company
...

Company model:

class Company < ActiveRecord::Base
  validates :company_name, presence: true, length: { maximum: 140}
  has_many :employees, class_name: "User",
                      dependent: :destroy

end

As for Controllers:

The users controller create method looks like this:

  def create
    @user = User.new(user_params)
    if @user.save
      @user.send_activation_email
      flash[:info] = I18n.t("controllers.users_controller.check_email")
      redirect_to root_url
    else
      render 'new'
    end
  end

When user_params are:

  private
    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation, company_attributes:[:company_name])
    end

The companies controller is empty..

And the form for submitting is constructed like this:

<% @user.build_company %>
<%= form_for(@user) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

  <%= f.label I18n.t("users.form.name") %>
  <%= f.text_field :name, class: 'form-control' %>

  <%= f.label I18n.t("users.form.email") %>
  <%= f.email_field :email, class: 'form-control' %>

  <%= f.fields_for :company do |builder| %>
    <%= builder.label I18n.t("users.form.company_name") %>
    <%= builder.text_field :company_name, :class => "form-control" %>
  <%end%>

  <%= f.label I18n.t("users.form.password") %>
  <%= f.password_field :password, class: 'form-control' %>

  <%= f.label I18n.t("users.form.password_confirmation") %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>

I think that is all the information necessary I can think of, If you need anything else, please tell me.

Now I hit a brick wall, and not really sure how to move on from this place. Where and How should I implement something that checks if the input company name already exists, and if it does, give the users' column company_id the existing company id from the companies table, and otherwise just create the company and get him the new id.

Also, on a side note, did I understood good that the dependent: :destroy at company model will cause that if I delete a company from the database, all the users that belonged to the company will also be deleted?(at least that's what I wanted to achieve).

I will appreciate all the help!

Best regards, Adam

Helban
  • 81
  • 12
  • 1
    I won't give you the full code. You are looking for something like http://stackoverflow.com/questions/3579924/accepts-nested-attributes-for-with-find-or-create – kiddorails Aug 30 '16 at 19:25
  • @kiddorails I kinda get the idea, but the whole topic just generates even more problems for me, like one of them is "undefined method `find_by_name' for # Did you mean? find_by" Not to mention other, Just had to revert to a previous commit cause i totally fked something up – Helban Aug 30 '16 at 20:13
  • 1
    `find_by_name` is a [dynamic method](http://railscasts.com/episodes/2-dynamic-find-by-methods) in rails. In your case, it might need `Company.find_by_company_name` – kiddorails Aug 30 '16 at 20:19
  • @kiddorails uh, oh... I...I think something went wrong. I tried to retest everything and ran rake db:reset and got a following error: NoMethodError: undefined method `company_name' for nil:NilClass /home/kramarz/workspace/praca/app/models/user.rb:116:in `autosave_associated_records_for_company' I have absolutely no clue why did that happen. This is the line 116 fro user.rb file: def autosave_associated_records_for_company # Find or create the company by name if new_company = Company.find_by_company_name(company.company_name) – Helban Aug 30 '16 at 20:27
  • @kiddorails actually i think we can disregard that error, it's something connected to my seeds. I've got other problem tho. If the company does exist, the user gets the id assigned correctly to the company_id field. However, if it's a new company, the company gets created, but the newly created users company_id field is empty. – Helban Aug 30 '16 at 20:38
  • 1
    Add `user.company_id = user.company.id` after you do `user.company.save!` – kiddorails Aug 30 '16 at 20:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/122234/discussion-between-kiddorails-and-helban). – kiddorails Aug 30 '16 at 20:50

2 Answers2

1

Add :autosave. With this you can then use autosave_associated_records_for_company to determine how to save the child when parent is saved.

class User < ActiveRecord::Base
  belongs_to :company, autosave: true
  accepts_nested_attributes_for :company

  def autosave_associated_records_for_company
    if company  
      # Find or create the company by name
      if new_company = Company.find_by_company_name(company.company_name)
        self.company = new_company
      else
        self.company.save!
        self.company_id = self.company.id
      end  
    end
  end
end
kiddorails
  • 12,961
  • 2
  • 32
  • 41
  • This answer EXACTLY solves my problem like it should! @kiddorails is a wizard and knows what he's talking about! Much appreciated! Thank you! :) – Helban Aug 30 '16 at 21:11
0

You can use before_save attributes for User model. Something like:

class User < ActiveRecord::Base
...
  belongs_to :company
  accepts_nested_attributes_for :company
  before_save :find_or_created_by_company_name
...
def find_or_created_company
  if Company.find(self.company_id).count == 0
    # There is no company existed
    self.company_id = Company.new()
    ... # Do whatever you want for your logical
  end
end

About the dependent: :destroy: you are right. Reference here

An Nguyen
  • 1,487
  • 10
  • 21
  • the def is wrongfuly named, but i figured that out. However the .count wont work for Company class for some reason. I see what you tried to present, but however i triend, it made no sense really... – Helban Aug 30 '16 at 20:15