Search code examples
ruby-on-railsfixtures

Label associations in Rails fixtures failing with "no columns named..."


I'm trying to use Label references for associations in my simple Rails (6) project but am getting a "no columns named..." error.

Among other things, I have orders.yml:

one:
  name: Dave Thomas
  address: MyText
  email: dave@example.org
  pay_type: credit_card

where pay_type is a reference to an entity in pay_types.yml:

credit_card:
  description: Credit Card

However, when I run any tests, I see a fixtures failure:

Error:
OrderTest#test_order_attributes_must_not_be_empty:
ActiveRecord::Fixture::FixtureError: table "orders" has no columns named "pay_type".
    /Users/sam/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/database_statements.rb:427:in `block in build_fixture_sql'

I can make this work by referencing IDs directly, but I'd rather not:

pay_type_id: 1

Fixtures.identify also works as per this answer (if I rename the file to have a .yml.erb extension):

pay_type_id: <%= Fixtures.identify(:credit_card) %>

but I'd really like to get my original form working.

Here are what the relevant models look like:

class Order < ApplicationRecord
  has_many :line_items, dependent: :destroy
  has_one :pay_type

  validates :name, :address, :email, presence: true
  validates_presence_of :pay_type
end
class PayType < ApplicationRecord
  has_many :order
end

and here's an extract from schema.yml:

  create_table "orders", force: :cascade do |t|
    t.string "name"
    t.text "address"
    t.string "email"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "pay_type_id", null: false
    t.index ["pay_type_id"], name: "index_orders_on_pay_type_id"
  end

  create_table "pay_types", force: :cascade do |t|
    t.string "description"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

Things I've tried that haven't helped:

Any ideas what I could be doing wrong?

Update: I imagine it's something I did wrong when switching from a pay_type string column to a pay_type_id reference on my Order model.

If you want to see the full project codebase (it's fairly small): https://github.com/sampart/rails-book-depot/tree/pay-type-label-reference

Context: I'm working through Agile Web Development with Rails 6 and am doing the extension task of moving the payment types into the database.


Solution

  • The problem was my association - has_one assumes a reference on the other side of the relationship, hence looking for a non-existent order_id column on PayType.

    When I changed my Order model to have this instead:

    belongs_to :pay_type
    

    then it worked.

    Although https://guides.rubyonrails.org/association_basics.html#the-belongs-to-association says "A belongs_to association sets up a one-to-one connection with another model", it turns out that they're not only for one-to-one relationships.

    The key thing is that belongs_to expects the foreign key column to be on the model on which the declaration itself is added.