所以,我有一个多态的Notification
模型,我希望能够过滤出notifiable_type
Comment
comment.user == current_user
的通知。换句话说,我想要所有通知记录 - 除了那些引用当前用户发表的评论的记录。
class Notification
belongs_to :notifiable, :polymorphic => true
scope :relevant, lambda { |user_id|
find(:all, :conditions => [
"notifiable_type != 'Comment' OR (notifiable_type = 'Comment' AND " <<
"comments.user_id != ?)",
user_id ],
:include => :comments
)
}
end
我不明白我需要做些什么才能获得评论?我需要告诉ActiveRecord外部加入notifiable_id
上的评论模型。
答案 0 :(得分:5)
首先,不推荐使用带参数的lambda范围。改为使用类方法:
class Notification
belongs_to :notifiable, polymorphic: true
def self.relevant(user_id)
# ...
end
end
我通常将范围功能移动到他们自己的模块中,但你可以把它留在那里。
接下来,不推荐使用find(:all)
,:conditions
也是如此。我们现在使用ActiveRelation queries。
不幸的是,ActiveRecord::Relation
API不够强大,无法满足您的需求,因此我们必须转而使用ARel。有点棘手,但出于安全原因,你绝对不想做字符串替换。
class Notification
belongs_to :notifiable, polymorphic: true
def self.relevant(user_id)
n, c = arel_table, Comment.arel_table
predicate = n.join(c).on(n[:notifiable_id].eq(c[:id]))
joins( predicate.join_sql ).
where{ ( notifiable_type != 'Comment' ) |
(( notifiable_type == 'Comment' ) & ( comments.user_id == my{user_id} ))
}
end
end
我在这里使用了ARel和Squeel的组合。 Squeel非常好,它应该是Rails的核心功能。我试着写那个没有Squeel的where子句,但是我放弃了这么困难。
很难在没有你的项目的情况下测试这样的东西,但希望这至少可以让你更接近。
答案 1 :(得分:0)
哎呀,你的代码有:include => :comments
,复数,这让我失望了。怎么样?
class Notification
belongs_to :notifiable, :polymorphic => true
scope :relevant, lambda { |user_id|
find(:all, :conditions => [
"notifiable_type != 'Comment' OR (notifiable_type = 'Comment' AND " <<
"comments.user_id != ?)",
user_id ],
:include => :notifiable
)
}
end
...然后Notification.relevant.first.notifiable
应该有效。来自文档:
多态关联支持预先加载。
class Address < ActiveRecord::Base belongs_to :addressable, :polymorphic => true end
试图急切加载可寻址模型的调用
Address.find(:all, :include => :addressable)
这将执行一个查询以加载地址并加载 每个可寻址类型一个查询的可寻址。例如,如果全部 可寻址者可以是Person或Company类,也可以是 将执行3个查询。要加载的可寻址类型列表是 在加载的地址的背面确定。 不支持此功能 如果Active Record必须回退到之前的实现 急切加载并将提升
ActiveRecord::EagerLoadPolymorphicError
即可。原因是 父模型的类型是一个列值,因此其对应的表名称 不能放在该查询的FROM / JOIN子句中。
(强调我的。)
答案 2 :(得分:0)
这就是我所采用的......我仍然希望有人能给我一个更好的方法。
Notification.find_by_sql( "SELECT * from Notifications " <<
"INNER JOIN comments ON notifiable_id = comments.id " <<
"WHERE notifiable_type != 'Comment' " <<
"OR (notifiable_type = 'Comment' AND comments.user_id = '#{user_id}')"
)