title: Creating and using multi-table join table in rails
body: <p>I have 3 tables, Users, Roles and Companies. A user can have multiple roles, without being part of a company. However, if a user is part of a company, their associated roles inside the company should be defined.</p>
  
  <p>To this end, I have created tables:</p>
  
  <ul>
  <li>roles_users (joins role and user tables)</li>
  <li>companies_users (joins the 3 table)</li>
  </ul>
  
  <p>The <code>companies_users</code> table has 3 columns, and a multicolumn unique prefix set.</p>
  
  <pre><code>create_table "companies_users", id: false, force: :cascade do |t|
    t.integer "role_id",    null: false
    t.integer "company_id", null: false
    t.integer "user_id",    null: false
    t.index ["role_id", "company_id", "user_id"], name: "index_companies_users_on_role_id_and_company_id_and_user_id", unique: true
    t.index ["role_id"], name: "index_companies_users_on_role_id"
    t.index ["company_id"], name: "index_companies_users_on_startup_id"
    t.index ["user_id"], name: "index_companies_users_on_user_id"
  end
  </code></pre>
  
  <p>I now have to create a form wherein, when a user signs up, can choose whether they want to provide their company details. In doing so, they'd also provide their role in those companies. The models are defined:</p>
  
  <h1>User.rb</h1>
  
  <pre><code>HABTM :company
  HABTM :roles
  accepts_nested_attributes_for :companies
  accepts_nested_attributes_for :roles
  </code></pre>
  
  <h1>Company.rb</h1>
  
  <pre><code>has_many :companies_users
  has_many :roles, through: :companies_users
  has_many :users, through: :companies_users
  </code></pre>
  
  <h1>Role.rb</h1>
  
  <pre><code>HABTM :companies
  HABTM :users
  </code></pre>
  
  <p>The models for join tables just define a <code>belongs_to</code> association. My form is created okay. It is sending the data as I desire:</p>
  
  <pre><code>{
    "utf8": "✓",
    "authenticity_token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "user": {
      "first_name": "My",
      "last_name": "Name",
      "location": "and location",
      "role_ids": [
        "2"
      ],
      "companies_attributes": {
        "0": {
          "name": "Company",
          "founding_year": "2017",
          "location": "Earth",
          "facebook": "facebook",
          "linkedin": "linkedin",
          "website": "website",
          "logo": "logo",
          "revenue_rate": "20",
          "private": "1",
          "role_ids": [
            "5", "8"
          ]
        }
      }
    },
    "commit": "Update User"
  }
  </code></pre>
  
  <p>and this fails, because rails tries to create a row as follows:</p>
  
  <pre><code>  SQL (0.2ms)  INSERT INTO "companies" ("name", "location", "founding_year", "website", "facebook", "linkedin", "revenue_rate", "created_at", "updated_at", "logo") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["name", "Company"], ["location", "Earth"], ["founding_year", 2017], ["website", "website"], ["facebook", "facebook"], ["linkedin", "linkedin"], ["revenue_rate", 20], ["created_at", 2017-06-18 05:08:16 UTC], ["updated_at", 2017-06-18 05:08:16 UTC], ["logo", "logo"]]
    SQL (0.7ms)  INSERT INTO "companies_users" ("role_id", "company_id") VALUES (?, ?)  [["role_id", 5], ["company_id", 122]]
     (0.2ms)  rollback transaction
  </code></pre>
  
  <p>How do I handle a 3-way join table successfully?</p>
  
  <hr>
  
  <h2>EDIT</h2>
  
  <p>The controller simply has the following code:</p>
  
  <pre><code>  def finish_signup
      if request.patch? and params[:user] #&amp;&amp; params[:user][:email]
        if @user.update(user_params)
          redirect_to root_path
        else
          @show_errors = true
        end
      end
  
      if request.get?
        @user = current_user
        @company = @user.companies.build
        @role = @user.roles.build
      end
    end
  </code></pre>