18322


条件が必要なときのみ通常使用している関連名はそのままにwhere句を使用したいと思い、関連の上書きを行う事で可能なのではと思い試してみています。

[code]

    class Hoge < ActiveRecord::Base
      belongs_to :common
      belongs_to :common_flag, -> { where(flag: 1) }, class_name: 'Common'
      def self.where_flag
        common = common_flag
        super
      end
    end
    
[/code]

railsのドキュメントを参考に、上記のような記述をしましたが、上手くいきませんでした。

[code]

    Hoge.where_flag
    
[/code]

と呼んだところ、common_flagが"undefined local variable or method"だと言われ、

[code]

    self.common_flag
    
[/code]

としてみたところ、common_flagが"undefined method"だと言われてしまいました。

正しくはどのように記述すればいいのでしょうか。


CC BY-SA 3.0
2015-06-09T12:19:17.340
11186
2016-04-06T02:44:52.537
2015-06-09T12:24:17.827
7352
7352
question
ruby-on-rails
associationをoverrideする方法


belongs_to は、インスタンスに紐づく関連レコードを取得するものです。

`#<Hoge id: 1, common_id: 1, ...`に対する`#<Common id: 1,
...`を取得するものですからHogeクラス自体からCommonのレコードを取得することはできません。

また`belong_to`は、命名規則通りであれば`common_id`に紐づく1つのレコードを取得するので`where(flag:
1)`は無意味であるため無視されます。

正しい記述方法は、実際どのようなレコードがあって、どういう式でどういう結果を得たいかがないと分かりません。(もしかしたら求めているのはscopeかもしれませんし、そもそもそんな処理を書く必要がないものかもしれません)

## コメントを受けての回答

関連付けは、関連付けの役目だけにすべきだと思います。  
(そもそも"上書き"なんてしたら。誰が現状どのような状態にあるか把握できるのでしょう？)  
やはりscopeで対応してはどうでしょうか。

[code]

    class School
      has_many :student
      scope :pref, ->(str){ where(prefecture: str) }
    end
    class Student
      belongs_to :school
      scope :boys, ->{ where(gender: 'male') }
    end
    
    School.first.students.boys
    
[/code]

scopeをmergeすることもできます。

[code]

    School.includes(:students).joins(:students).merge( Student.boys )
    Student.includes(:school).joins(:school).merge( School.pref('tokyo') }
    
[/code]

上記コードは、arelでも掛けます。

[code]

    student_cond = Student.arel_table[:gender].eq('male')
    student_cond.to_sql  #=> students.gender = 'male'
    School.includes(:students).joins(:students).where(student_cond)
    
[/code]

ただしこの場合は、includesを使わないと  
最初のSchool/Studentのレコードを取得して、関連するstudents/school無指定で再取得試みるので注意が必要です。

ちょっとトリッキーだと。こんなこともできます。

[code]

    scope :has, ->(cond){ where(cond) }
    School.incldues(:students).joins(:students).merge( Student.has(gender: 'male') )
    
[/code]


CC BY-SA 3.0
2015-11-02T08:55:23.940
18322
2015-12-07T11:02:08.050
2015-12-07T11:02:08.050
8335
8335
11186
answer