【问题标题】:Activerecord has_many :through through multiple modelsActiverecord has_many:通过多个模型
【发布时间】:2016-04-20 16:22:20
【问题描述】:

我正在尝试使用user.comments 访问给定用户的所有 cmets。查询将通过两个不同的模型,它们可能都返回结果。我的关系设置如下:

class User < ActiveRecord::Base
  has_many :organisers
  has_many :participants
  has_many :comments, through: :participants / :organisers (see explenation below)
end

class Organiser < ActiveRecord::Base
  belongs_to :user
end

class Participant  < ActiveRecord::Base
  belongs_to :user
end

class Comment < ActiveRecord::Base
  belongs_to :organiser
  belongs_to :participant
end

验证评论属于参与者或组织者。

我不知道该怎么做。我试过了

has_many :comments, through: :participants
has_many :comments, through: :organisers

has_many :comments, through: [:organisers, :participants]

但最后一个不是铁轨。有没有合适的方法来做到这一点?谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 activerecord


    【解决方案1】:
    has_many :comments, ->(user) {
      unscope(where: :user_id).
      left_joins(:organizer, :participant).
      where('organizers.user_id = ? OR participants.user_id = ?', user.id, user.id)
    }
    

    unscope 是删除comments.user_id = ? 子句(定义has_many 关系时默认添加)。 left_joinsComment 上调用,因此您需要传入 Comment 上定义的关系名称,因此在此示例中使用单数。

    【讨论】:

      【解决方案2】:

      经过多次尝试,我找到了解决方案。您可以在 User 模型的最后一个 has_many 句子中使用带参数的范围:

      has_many :comments, -> (user) {where organiser: user.organisers}, through: :participants
      

      “user”参数代表正在调用 cmets 方法的用户对象。

      【讨论】:

        【解决方案3】:

        因为我们不能在这里使用has_many, through,因为comments 来自organisersparticipants。我只是认为这里有两种解决方案:

        解决方案#1定义comments方法:

        class User < ActiveRecord::Base
          def comments
            Comment.joins([{organiser: :user}, {participant: :user}])
                   .where(users: {id: self.id})
          end
        end
        

        那么您查找 cmets 的查询是:

        User.first.comments
        

        解决方案#2Comment中使用范围

        class Comment < ActiveRecord::Base
          scope :from_user, -> (user) { 
            joins([{organiser: :user}, {participant: :user}]).where(users: {id: user.id}) 
          }
        end
        

        所以你的查询会是这样的:

        user = User.first
        comments = Comment.from_user(user)
        

        【讨论】:

        • 我不相信这些解决方案会起作用,因为joins 语句实际上充当了两个提供的参数之间的AND,而不是所需的OR
        【解决方案4】:

        由于我们不能使用has_many,所以通过这里,因为cmets 来自组织者和参与者。我只是认为这里有两种解决方案:

        基本上,您仍然可以在此处使用 Rails 更改外键以自动接受 self.id

        User.first.comments
        
        class User
          has_many :comments, -> { joins([{ organiser: :user }, { participant: :user }]) }, through: :participants, foreign_key: "users.id"
        end
        

        【讨论】:

          【解决方案5】:

          对于使用多态关联遇到此问题的任何人,以下内容对我有用,灵感来自 magni- 和 Carlos Jimenez 的回答:

          has_many :comments, -> (user) {
            unscope(where: :user_id).
            where(commentable: [user.organizers, user.participants])
          }
          

          【讨论】:

            【解决方案6】:

            我相信你的关联会被混淆,因为 user.cmets 不知道它是通过参与者还是组织者,所以最好的选择是声明两个不同的连接(使用不同的名称):

            http://guides.rubyonrails.org/association_basics.html#self-joins

            【讨论】:

            • 将此请求视为请求user.participant_or_organizer_comments
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多