ActiveRecord has_many through limited association with arg

I saw several answers to questions that relate to how to use area blocks in ActiveRecord associations, which include passing the object itself to a block, for example ...

class Patron < ActiveRecord::Base has_many :bars, ->(patron) { baz: patron.blah }, foreign_key: :somekey, primary_key: :somekey end class Bar < ActiveRecord::Base belongs_to :patron, ->(bar) { blah: bar.baz }, foreign_key: :somekey, primary_key: :somekey end 

The use of explicit PKs and FKs here is related to the inherited relationship between base tables. There are many hundreds of millions of "patrons" in the production system.

As a clarification, re @TJR - the relationship between Patron and Bar is a valid compound foreign key in the fields: somekey and: baz (or: blah in the opposite direction). ActiveRecord: the foreign_key option does not allow arrays.

I found that, unfortunately, this prevents subsequent has_many: throughs actions from expected.

 class Patron < ActiveRecord::Base has_many :bars, ->(patron) { baz: patron.blah }, foreign_key: :somekey, primary_key: :somekey has_many :drinks, through: :bars end 

Using pass-through associations creates errors such as ...

ArgumentError: invalid number of arguments (0 to 1)

The connection between the bar and drinks is the classic has_many with a standard foreign and primary key (bar_id, id).

I came up with some ugly jobs that let me accomplish the desired functionality, but it all smells awful. So far, the best ones look like

 class Patron < ActiveRecord::Base has_many :bars, ->(patron) { baz: patron.blah }, foreign_key: :somekey, primary_key: :somekey def drinks bars.drinks end end 

I got the existing Bar class and consists of many hundreds of millions of records, as I mentioned, which makes it difficult to change the database.

Some posts seemed to offer a dynamic evaluation of the string inside proc to avoid having to pass the current cartridge object, but as mentioned in other posts, this does not work.

Please advise me what I can do to make has_many work work.

+5
source share
1 answer

I just tried similar associations in Rails 4.2. It works very well:

 class Patron < ActiveRecord::Base has_many :bars, ->(patron) { where(baz: patron.blah) }, foreign_key: :patron_id, primary_key: :id has_many :drinks, through: :bars end class Bar < ActiveRecord::Base belongs_to :patron, ->(bar) { where(blah: bar.baz) }, foreign_key: :patron_id, primary_key: :id has_many :drinks end class Drink < ActiveRecord::Base end 

Check associations:

 > p1 = Patron.first > p1.drinks Drink Load (0.8ms) SELECT "drinks".* FROM "drinks" INNER JOIN "bars" ON "drinks"."bar_id" = "bars"."id" WHERE "bars"."patron_id" = 1 AND "bars"."baz" = 1 [["patron_id", 1], ["baz", 1]] => #<ActiveRecord::Associations::CollectionProxy [#<Drink id: 3, name: "drink 3", bar_id: 2, created_at: "2017-04-07 03:30:06", updated_at: "2017-04-07 03:30:06">]> 
0
source

Source: https://habr.com/ru/post/1244676/


All Articles