Home > other >  How to access other columns of has_many through table
How to access other columns of has_many through table

Time:08-24

I am working on rails 7 with 2 models which are Partner and Package, and I would like to assign the packages to the partner, but they need to be assigned together with their orders.

For example, if I assign package#A and package#B to the partner with 1st and 2nd order respectively, then package#A will be considered as a small package and package#B will be considered as a medium package.

So, I have created PartnerPackage to link them together (with has_many through:) and also added package_order column to contain the package's order.

Question

What is the best way to retrieve all of the packages that belong to a specific partner, and also package_order as well? Thank you so much for your answer!

Partner.rb

class Partner < ApplicationRecord
  has_many :partner_packages, dependent: :destroy
  has_many :packages, through: :partner_packages
end

Package.rb

class Package < ApplicationRecord
  has_many :partner_packages, dependent: :destroy
  has_many :packages, through: :partner_packages
end

PartnerPackage.rb

class PartnerPackage < ApplicationRecord
  belongs_to :partner
  belongs_to :package

  validates :package_order, presence: true
end

CodePudding user response:

There's a virtually hidden feature of Rails that allows you to add any other columns to an SQL select and Rails makes them available as readonly attributes in the resulting object, eg:

[24] pry(main)> ff = Foo.select("*, current_timestamp as now").first
  Foo Load (0.3ms)  SELECT *, current_timestamp as now FROM "foos" ORDER BY "foos"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Foo:0x0000000106442580 id: 1, name: "First Foo", age: 1, created_at: Thu, 21 Jul 2022 00:13:26.758228000 UTC  00:00, updated_at: Thu, 11 Aug 2022 15:23:14.015000000 UTC  00:00>
[25] pry(main)> ff.now
=> "2022-08-18 16:40:25"

So then you can use this to pull out the fields in a hmt table because you know that the SQL will include a join on that table:

partner.packages.select("packages.*, partner_packages.package_order")

Now if you want to get fancy you can use Arel to avoid the string table names, but that's the basic idea.

  • Related