Rails模型/查询“参加活动的联系人列表中的人员简介”

时间:2014-10-02 02:00:57

标签: ruby-on-rails activerecord

所以这里涉及很多关系。最终目标是在活动视图上显示来自current_user的联系人列表中参加活动的人。当前的模型布局如下:

# Table name: profiles
#  id                  :integer          not null, primary key
#  profileable_id      :integer
#  profileable_type    :string(255)
class Profile < ActiveRecord::Base
  belongs_to :profileable, polymorphic: true
  has_many :events, as: :eventable, dependent: :destroy
end

# Table name: events
#  id             :integer          not null, primary key
#  eventable_id   :integer
#  eventable_type :string(255)
class Event < ActiveRecord::Base
  belongs_to :eventable, polymorphic: true
  has_many :attendants, dependent: :destroy
end

# Table name: attendants
#  id                    :integer          not null, primary key
#  referrer_profile_id   :integer
#  event_id              :integer
#  responding_profile_id :integer
class Attendant < ActiveRecord::Base
  belongs_to :event
end

# Table name: contacts
#  id         :integer          not null, primary key
#  user_id    :integer
class Contact < ActiveRecord::Base
  belongs_to :user
  has_one :profile, as: :profileable, dependent: :destroy
end

显然,一些更多关系相关的行会有所帮助,一些范围和一些东西可以帮助加入(我相信)。

我希望做的事情就像:

@attendants = Attendant.where(event_id: @event.id)
@contacts = Contacts.where(user_id: current_user.id)
@result = @attendents.select {|i| @contacts.any? {|c| i.responding_profile_id == c.profile.id } }

据我所知,这是效率最低的方法。如果您可以帮助我使用正确的加入合并范围以及其他拥有/属于关系行完成这一点我将永远感激不尽!


这是关系模型图。配置文件和事件是多态的。服务员是一个关系表。 diagram

我查询了Attendant和Profile为JSON的示例。也许这会有所帮助。

Contact.find(8).profile.as_json
  Contact Load (0.6ms)  SELECT  "contacts".* FROM "contacts"  WHERE "contacts"."id" = $1 LIMIT 1  [["id", 8]]
  Profile Load (0.3ms)  SELECT  "profiles".* FROM "profiles"  WHERE "profiles"."profileable_id" = $1 AND "profiles"."profileable_type" = $2 LIMIT 1  [["profileable_id", 8], ["profileable_type", "Contact"]]
 => {"id"=>11, "first_name"=>"Apple", "last_name"=>"Dumpling", "profileable_id"=>8, "profileable_type"=>"Contact", "created_at"=>Fri, 10 Oct 2014 02:21:20 UTC +00:00, "updated_at"=>Fri, 10 Oct 2014 02:21:20 UTC +00:00} 

Attendant.second.as_json
  Attendant Load (0.8ms)  SELECT  "attendants".* FROM "attendants"   ORDER BY "attendants"."id" ASC LIMIT 1 OFFSET 1
 => {"id"=>2, "confirmation"=>"attending", "referrer_profile_id"=>1, "responding_profile_id"=>8, "event_id"=>1, "created_at"=>Fri, 10 Oct 2014 17:46:44 UTC +00:00, "updated_at"=>Fri, 10 Oct 2014 17:46:44 UTC +00:00} 

3 个答案:

答案 0 :(得分:1)

我无法在没有您的数据库的情况下对其进行测试,但是查看您的架构,这应该返回当前用户参与给定事件的每个联系人的个人资料。

 Profile.where('id 
   IN (SELECT attendants.responding_profile_id FROM attendants WHERE attendants.responding_profile_id 
   IN (SELECT profiles.id FROM profiles WHERE profiles.id 
   IN(SELECT contacts.profile_id FROM contacts WHERE contacts.user_id = ?)) 
   AND attendants.event_id = ?)', current_user.id, @event.id)

答案 1 :(得分:1)

我不确定这是否正确但是我在这里看到了你的架构:

Profile.select(Arel.star).where(
  Profile.arel_table[:profileable_id].in(
    Event.select(Attendant.arel_table[:responding_profile_id]).where(
      Event.arel_table[:id].eq(@event.id).and(
        Attendant.arel_table[:responding_profile_id].in(
         Attendant.select(Attendant.arel_table[:responding_profile_id]).where(
            Contact.arel_table[:user_id].eq(current_user_id)
          ).joins(
            Attendant.arel_table.join(Contact.arel_table).on(
              Attendant.arel_table[:responding_profile_id].eq(Contact.arel_table[:id])
            ).join_sources
          ).ast
        )
      )
    ).ast
  )
)

这是用于参考的SQL:

SELECT * from Profile 
    where Profile.profileable_id in 
        (select Attendant.responding_profile_id from Event 
            where Event.id = @event.id
            and Attendant.responding_profile_id in
                (select Attendant.responding_profile_id from Attendant inner join Contact 
                    on Attendant.responding_profile_id = Contact.id
                    where Contact.user_id = current_user_id
                )
        )

答案 2 :(得分:0)

这个问题是多态的配置文件意味着它通过它的关联表选择它的父母。在我的问题中,我曾要求使用相同的ID /类型为两个不同的父项找到相同的配置文件。这是不可能的,因为它不一样。 当前代码不起作用。为了解决这个问题,我在 original_profile_id Contact添加了一个字段,该字段在人员的个人资料重复时被写入,以便始终拥有对原始资源的引用。现在突然间,因为不可能,所以很难复杂,很容易得到补救。