特定类型的多态所属的关联 [英] Association for polymorphic belongs_to of a particular type

查看:29
本文介绍了特定类型的多态所属的关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 Rails 比较陌生.我想向使用多态关联的模型添加关联,但仅返回特定类型的模型,例如:

I'm relatively new to Rails. I would like to add an association to a model that uses the polymorphic association, but returns only models of a particular type, e.g.:

class Note < ActiveRecord::Base
  # The true polymorphic association
  belongs_to :subject, polymorphic: true

  # Same as subject but where subject_type is 'Volunteer'
  belongs_to :volunteer, source_association: :subject
  # Same as subject but where subject_type is 'Participation'
  belongs_to :participation, source_association: :subject
end

通过阅读有关 ApiDock 的关联,我尝试了多种组合,但似乎没有完全按照我的意愿行事.这是我迄今为止最好的:

I've tried a vast array of combinations from reading about the associations on ApiDock but nothing seems to do exactly what I want. Here's the best I have so far:

class Note < ActiveRecord::Base
  belongs_to :subject, polymorphic: true
  belongs_to :volunteer, class_name: "Volunteer", foreign_key: :subject_id, conditions: {notes: {subject_type: "Volunteer"}}
  belongs_to :participation, class_name: "Participation", foreign_key: :subject_id, conditions: {notes: {subject_type: "Participation"}}
end

我希望它通过这个测试:

And I want it to pass this test:

describe Note do
  context 'on volunteer' do
    let!(:volunteer) { create(:volunteer) }
    let!(:note) { create(:note, subject: volunteer) }
    let!(:unrelated_note) { create(:note) }

    it 'narrows note scope to volunteer' do
      scoped = Note.scoped
      scoped = scoped.joins(:volunteer).where(volunteers: {id: volunteer.id})
      expect(scoped.count).to be 1
      expect(scoped.first.id).to eq note.id
    end

    it 'allows access to the volunteer' do
      expect(note.volunteer).to eq volunteer
    end

    it 'does not return participation' do
      expect(note.participation).to be_nil
    end

  end
end

第一个测试通过,但不能直接调用关系:

The first test passes, but you can't call the relation directly:

  1) Note on volunteer allows access to the volunteer
     Failure/Error: expect(note.reload.volunteer).to eq volunteer
     ActiveRecord::StatementInvalid:
       PG::Error: ERROR:  missing FROM-clause entry for table "notes"
       LINE 1: ...."deleted" = 'f' AND "volunteers"."id" = 7798 AND "notes"."s...
                                                                    ^
       : SELECT  "volunteers".* FROM "volunteers"  WHERE "volunteers"."deleted" = 'f' AND "volunteers"."id" = 7798 AND "notes"."subject_type" = 'Volunteer' LIMIT 1
     # ./spec/models/note_spec.rb:10:in `block (3 levels) in <top (required)>'

<小时>

为什么?

我想这样做的原因是因为我正在构建一个基于解析查询字符串的范围,包括连接到各种模型/等;用于构造范围的代码比上面的复杂得多 - 它使用 collection.reflections 等.我当前的解决方案适用于此,但它冒犯了我我不能直接从Note 的一个实例.


Why?

The reason I want to do it this way is because I'm constructing a scope based on parsing a query string including joining to various models/etc; the code used to construct the scope is considerably more complex than that above - it uses collection.reflections, etc. My current solution works for this, but it offends me I can't call the relations directly from an instance of Note.

我可以把它分成两个问题来解决:直接使用作用域

I could solve it by splitting it into two issues: using scopes directly

  scope :scoped_by_volunteer_id, lambda { |volunteer_id| where({subject_type: 'Volunteer', subject_id: volunteer_id}) }
  scope :scoped_by_participation_id, lambda { |participation_id| where({subject_type: 'Participation', subject_id: participation_id}) }

然后只为 note.volunteer/note.participation 使用一个 getter,它只返回 note.subject 如果它有正确的 subject_type(否则为零)但我想在 Rails 中一定有更好的方法吗?

and then just using a getter for note.volunteer/note.participation that just returns note.subject if it has the right subject_type (nil otherwise) but I figured in Rails there must be a better way?

推荐答案

我遇到了类似的问题.我最终通过使用如下所示的自引用关联,找出了最好和最强大的解决方案.

I had bump into the similar problem. and I finally ironed out the best and most robust solution by using a self reference association like below.

class Note < ActiveRecord::Base
  # The true polymorphic association
  belongs_to :subject, polymorphic: true

  # The trick to solve this problem
  has_one :self_ref, :class_name => self, :foreign_key => :id

  has_one :volunteer, :through => :self_ref, :source => :subject, :source_type => Volunteer
  has_one :participation, :through => :self_ref, :source => :subject, :source_type => Participation
end

清洁&简单,仅在 Rails 4.1 上测试过,但我想它应该适用于以前的版本.

Clean & simple, only tested on Rails 4.1, but I guess it should work for previous versions.

这篇关于特定类型的多态所属的关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆