Mutafaf
Mutafaf

Reputation: 126

Rails: Polymorphism, undefined method `primary_key' for String:Class

I am trying to achieve polymorphic behaviour in my rails application. I have 3 models:

Transaction has a Party(either customer or supplier).

I have created a model Party as concern when I am trying to save or update I receive this error.

Error on save

The models are as follows:

party.rb

module Party
  extend ActiveSupport::Concern

  included do
    has_many :transactions, :as => :party
  end
end

customer.rb

class Customer < ApplicationRecord
  include Party
  ....
end

supplier.rb

class Supplier < ApplicationRecord
  include Party
  ....
end

transaction.rb

class Transaction < ApplicationRecord
  belongs_to :party, polymorphic: true

  ....
end

When hit save the params received at server are

Parameters: {"authenticity_token"=>"....", "transaction"=>{"party"=>"4", ...}, "commit"=>"Update Transaction", "id"=>"2"}

Hope someone can figure out the issue. Thanks for your time.

Here is the transactions schemea.

create_table "transactions", force: :cascade do |t|
    t.date "date"
    t.string "transaction_type"
    t.integer "supplier_id"
    t.integer "customer_id"
    t.string "party_type", null: false
    t.bigint "party_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["party_type", "party_id"], name: "index_transactions_on_party_type_and_party_id"
  end

Upvotes: 2

Views: 1410

Answers (4)

Neel
Neel

Reputation: 1

There is problem with params, it contains "party" => "4", for polymorphic association you can have one of the following:

  1. "transaction"=>{"party_type" => "Customer", "party_id" => "4", ... }
  2. "transaction"=>{"party" => <Customer OR supplier object>, ... }

Rails will try transactioin.party.class.primary_key to find out primary_key column, in above case it will get String for transaction.party.class and hence it will raise NoMethodError (undefined method primary_key' for String:Class)`.

You can try assigning transaction.party = "4" in rails console, you will get same error.

Upvotes: 0

Abou Bakr Gban&#233;
Abou Bakr Gban&#233;

Reputation: 11

According to what you exposed here, this issue is caused by the params sent. You need to make sure that "party_id" holds the polymorphic resource id and "party_type" either "customer" or "supplier". Also as you are using rails' polymorphic behaviour, "supplier_id" and "party_id" columns are no longer relevant.

Upvotes: 1

Rudy Zidan
Rudy Zidan

Reputation: 101

If you want to achieve Polymorphism using Party you will have to change the code as the following:

  1. Create table called "parties" contains resource_id (same as the other models type) and resource_type (String).
  2. declare a relation inside your Party model "belongs_to :resource, polymorphic: true"
  3. Update the Customer and Supplier model to contain "has_many / has_one :party(eis), as: :resource".

Your code treat party as a module which does not implement primary_key method as the activerecord use it to build the associations on create or update.

Upvotes: 1

Anand Bait
Anand Bait

Reputation: 371

Can you add transactions table schema in question?
I am assuming that the transactions table has party_id and party_type.
So if the columns are present then you need check view so that in params controller should receive like "transaction"=>{"party_id"=>"4", "party_type"=>"custmer"...}

Upvotes: 2

Related Questions