Anders
Anders

Reputation: 2941

Rails 5: Update attribute in has many through join table

I'm currently working on a webshop and I'm using Rails 5. I have the following models and relationships:

# Products
class Product < ApplicationRecord
  has_many :product_variants
  has_many :variants, through: :product_variants
  ...

class Variant < ApplicationRecord
  has_many :product_variants
  has_many :products, through: :product_variants
  ...

# My join table between Product and Variant 
class ProductVariant < ApplicationRecord
  belongs_to :price, optional: true
  belongs_to :product, optional: true
  belongs_to :variant, optional: true

My ProductVariant model have an additional attribute that I would like to be updatable, t.integer "quantity". I'm a bit lost when it comes to update this attribute in a form_for.

My current solution for the form looks like this (I use HAML):

= form_for @product, html: { method: :patch } do |product_builder|

  = product_builder.fields_for :product_variants, product_variant do |variant_builder|

    = variant_builder.hidden_field :variant_id, value: product_variant.variant.id

    = variant_builder.number_field :quantity

    = variant_builder.submit

But it doesn't work properly. Feels like would have been easier if the join table had an ID column, but I guess that is redundant in the database. It currently seems to create another instance of a ProductVariant when I click the submit button.

Any idea on what I should to to properly update my quantity attribute in my join table?

For completion

This is what gets logged when I click submit:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"uisxjfvj9LxZVJWcDVos66tJWNfHkld5+/gdfGv1D2WZsrLJcH7KLxb5eSDAYIL23mEEho18Pv/53bSEP8cC9A==", "product"=>{"product_variants_attributes"=>{"0"=>{"variant_id"=>"1", "product_id"=>"11", "quantity"=>"20", "id"=>""}}}, "commit"=>"Update Product variant", "id"=>"11"} Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", 11], ["LIMIT", 1]] Unpermitted parameter: :id (0.1ms) begin transaction Brand Load (0.2ms) SELECT "brands".* FROM "brands" WHERE "brands"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]] Variant Load (0.2ms) SELECT "variants".* FROM "variants" WHERE "variants"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] Brand Exists (0.2ms) SELECT 1 AS one FROM "brands" WHERE "brands"."name" = ? AND ("brands"."id" != ?) LIMIT ? [["name", "Fredric Malle"], ["id", 4], ["LIMIT", 1]] SQL (0.4ms) INSERT INTO "product_variants" ("variant_id", "product_id", "quantity") VALUES (?, ?, ?) [["variant_id", 1], ["product_id", 11], ["quantity", 20]] (2.7ms) commit transaction (0.2ms) SELECT COUNT(*) FROM "note_parts" INNER JOIN "product_note_parts" ON "note_parts"."id" = "product_note_parts"."note_part_id" WHERE "product_note_parts"."product_id" = ? [["product_id", 11]] Redirected to http://localhost:3000/products/11/edit Completed 302 Found in 15ms (ActiveRecord: 4.0ms)

Upvotes: 0

Views: 584

Answers (1)

EJAg
EJAg

Reputation: 3308

You're doing a has_many :though. In this case, the join table needs to have a primary key (usually :id). Otherwise you can't access the join table directly like what you want here.

On the other hand, if you don't need direct access to the join table (e.g. no extra columns there), then you can set up a has_and_belongs_to_many, with no id column for the join table.

Upvotes: 1

Related Questions