简体   繁体   中英

"Can't write unknown attribute" to HABTM join table when using custom foreign key

A User can HABTM Games and a Game can HABTM Users as Storytellers, to differentiate them from a later relationship where a Game will have many Users as Participants.

Rails throws the error "can't write unknown attribute `user_id'" when I attempt to add the user-input User objects to @game.storytellers via the create method in the Games controller.

I'm pretty sure the problem lies in my last migration (at the bottom of this post).

models/user.rb

class User < ActiveRecord::Base
    has_and_belongs_to_many :games, association_foreign_key: "storyteller_id"
end

models/game.rb

class Game < ActiveRecord::Base
    has_and_belongs_to_many :storytellers, class_name: "User", 
                                           foreign_key: "storyteller_id"
    attr_accessor :storyteller_group
end

controllers/games.rb

  def create
    @game = Game.new(game_params)
    @game.storytellers << params[:game][:storyteller_group].split(",").collect { |n| User.find_by(name: n) }

    respond_to do |format|
      if @game.save
        format.html { redirect_to @game, notice: 'Game was successfully created.' }
        format.json { render :show, status: :created, location: @game }
      else
        format.html { render :new }
        format.json { render json: @game.errors, status: :unprocessable_entity }
      end
    end
  end

views/games/_form.html.erb

<%= form_for(@game) do |f| %>
    [snip]

    <!-- Additional storytellers-->
    <div class="field">
        <%= f.label :storyteller_group, id: "create-game" %>
        <div class="input">
            <%= f.text_field :storyteller_group, value: current_user.name %>
        </div>
    </div>

    [snip]
<% end %>

db/migrations/create_users.rb

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.index :name

      t.string :email
      t.index :email

      [snip]

      t.timestamps
    end
  end
end

db/migrations/create_games.rb

Class CreateGames < ActiveRecord::Migration
  def change
    create_table :games do |t|
      t.string :name
      t.text :description
      t.string :source

      t.timestamps
    end
  end
end

db/migrations/games_users.rb

class GamesUsers < ActiveRecord::Migration
  def change
    create_table :games_users, id: false do |t|
      t.belongs_to :game, index: true
      t.integer :storyteller_id, index: true
    end
  end
end

You have written your HABTM foreign keys definitions in just the opposite way. Quoting from Rails guides :

:association_foreign_key

By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix _id added. The :association_foreign_key option lets you set the name of the foreign key directly.

and

:foreign_key

By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix _id added. The :foreign_key option lets you set the name of the foreign key directly

So, the following should work:

class User < ActiveRecord::Base
  has_and_belongs_to_many :games, foreign_key: "storyteller_id"
end

class Game < ActiveRecord::Base
  has_and_belongs_to_many :storytellers, class_name: "User", 
                                         association_foreign_key: "storyteller_id"
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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