0

にスコープ条件文で:「を通じてhas_manyの:assocation」の定義私は次のようになりますスキーマ持つモデルによる

create_table "customers" do |t| 
    t.integer "customer_number" 
end 

create_table "past_payments" do |t| 
    t.integer "customer_number" 

    t.datetime "transaction_date" 
    t.integer "arbitrary_sequence_number" 
end 

create_table "payment_details" do |t| 
    t.datetime "transaction_date" 
    t.integer "arbitrary_sequence_number" 
end 

TLを、DRスキーマから - お客様は通過past_paymentに関連していますプライマリ/外部キー。また、PastPaymentは、そのtransaction_dateとarbitrary_sequence_numberが等しい場合、単一のPaymentDetailに関連付けられます。支払いと詳細に正式な主キー/外部キーの関係はありません。

私に次のActiveRecordモデル与え:Customer has_many :past_paymentsPastPayment has_one :payment_detailので

class Customer < ActiveRecord::Base 
    has_many :past_payments, foreign_key: :customer_number, primary_key: :customer_number 

    has_many :payment_details, through: :past_payments # unfortunately, broken 
end 

class PastPayment < ActiveRecord::Base 
    has_one :payment_detail, ->(past_payment) { 
    where(arbitrary_sequence_number: past_payment.arbitrary_sequence_number) 
    }, foreign_key: :transaction_date, primary_key: :transaction_date 
end 

を、私はそのようなCustomer has_many :payment_details, through: :past_paymentsことを定義することができます関連があると思うだろうが、私は仕事にそれを得ることができませんhas_one :payment_detailの関連付けで定義されている範囲のためです。

具体的には、Customer.payment_detailsを呼び出すと、NoMethodError: undefined method 'arbitrary_sequence_number' for #<Customer:0x2i8asdf3>が呼び出されます。それで、顧客はPastPaymentとは対照的に、私の範囲に渡っているように見えます。

お客様はhas_many :payment_detailsの関連付けを定義することはできますか?私は何か間違っているのですか?

明確にするには、Customer.where(some_conditions).includes(:payment_details)と言うことができ、2つのクエリだけを実行したいので、関連なしでそれを達成する方法があれば、私はそれを公開しています。

注:このデータベースは変更できません。それは他のアプリケーションが書き込むデータベースで、そこから読む必要があります。

私の質問とは無関係に、私は現在作業している回避策です。

class Customer < ActiveRecord::Base 
    attr_writer :payment_details 

    def payment_details 
    @payment_details ||= Array(self).with_payment_details.payment_details 
    end 

    module InjectingPaymentData 
    def with_payment_details 
     results = self.to_a 
     return self unless results.first.is_a?(Customer) 

     user_ids = results.collect(&:id) 

     # i've omitted the details of the query, but the idea is at the end of it 
     # we have a hash with the customer_number as a key pointing to an array 
     # of PaymentDetail objects 
     payment_details = PaymentDetails.joins().where().group_by(&:customer_number) 

     results.each do |customer| 
     customer.payment_details = Array(payment_details[customer.customer_number]) 
     end 
    end 
    end 
end 

ActiveRecord::Relation.send(:include, Customer::InjectingPaymentData) 
Array.send(:include, Customer::InjectingPaymentData) 

ということで、私は、最小限の照会で、次のようなことを行うことができます:

@customers = Customer.where(id: 0..1000).with_payment_details 
@customers.each { |c| do_something_with_those_payment_details } 

問題を適切関連付けを使用する方法はありません場合、私は、このソリューションが批判しているさせていただきそのアプローチで?

答えて

1

あなたがより良いのActiveRecordの「複合主キー」を処理するためにこの宝石を活用することができます:https://github.com/composite-primary-keys/composite_primary_keys

class Customer < ActiveRecord::Base 
    has_many :past_payments, foreign_key: :customer_number, primary_key: :customer_number 

    has_many :payment_details, through: :past_payments # this works now 
end 

class PastPayment < ActiveRecord::Base 
    has_one :payment_detail, foreign_key: [:transaction_date, :arbitrary_sequence_number], 
          primary_key: [:transaction_date, :arbitrary_sequence_number] 
end 
関連する問題