我希望将我的故事索引与“已浏览的故事”(标记为用户查看的故事)进行升序排序,将它们放在用户的Feed中的最后一个,而“未查看”的故事首先出现。
我已经跟踪用户是否看过一个名为View的模型的故事。 客户端上的滚动事件发送ajax请求,该请求使用story_id和User_id创建视图:
class ViewsController < ApplicationController
def create
@user = current_user
@story = Story.find(params[:story_id])
@view = @user.views.find_or_create_by!(story_id: @story.id)
render json: {viewed: true, id: @story.id}
end
end
模型如下关联:
class View < ActiveRecord::Base
belongs_to :user
belongs_to :story
end
class User < ActiveRecord::Base
has_many :views
has_many :favorites
has_many :stories, through: :favorites
end
class Story < ActiveRecord::Base
serialize :viewed_by_users, Array
has_many :views
has_many :favorites
has_many :users, through: :favorites
end
正如您所看到的,我已经在使用连接通过表来收藏,因此@ user.stories或@ story.users反映了收藏夹而不是视图。 如果我想检查一个故事是否已被用户查看,我可以这样做:
current_user.views.exists?(story: @story)
#Returns true or false when examining an instance of story.
我还为了方便而序列化了一个关于故事的故事,其中填充了用户ID,表示哪些用户查看过故事。 我可能想稍后取消我可以开始工作的属性。与此同时,我可以这样检查:
stories_not_viewed = Story.all.select { |s| s.viewed_by_users.include?(current_user) }
#returns an array of stories that have been viewed by current_user.
现在我正在努力在我的模型中创建一个范围,或者在我的控制器中创建一个.order查询,它将用户查看过的故事放在索引的尾端(升序)。
我有一个这样的故事控制器(有分页):
class StoriesController < ApplicationController
def index
page = params[:page].try(:to_i) || 1
story_index = page - 1
@stories = Story.includes(:users).limit(15).offset(story_index * 15)
render json: @stories
end
end
我无法弄清楚如何编写一个考虑我的视图关联的默认范围。看来我必须将current_user传递给模型,编写一些逻辑来查找用户id是否在每个故事的View关联中,如果是,则最后对这些故事进行排序(升序)。我在这里尝试了很多不同的课程方法但是对于我的生活,我无法弄清楚这一点。任何与此类似的例子都会受到赞赏。
另一种选择是如果我稍微改变我的设计,我可以让@stories索引简单地返回未查看的故事并为查看的故事创建不同的端点,让用户使用显示“show”的按钮切换前端视图查看故事“或”显示未审查的故事“。
我也无法做到这一点。我需要它来处理我的活动记录查询而不是数组,所以我可以保持我的分页。 我想我需要这样的事情:
@stories = Story.where.not viewed_by_users.include?(current_user) #...etc
显然这不是正确的查询代码,这是我正在努力学习并试图了解更多信息。它显然需要像:
where("viewed_by_users != ?", current_user)
...除了current_user是数组中的众多用户之一,因此在这种情况下不会完全正常工作。
我一直在努力解决所有这些问题但是没有任何工作要做。在这一点上,我很乐意让任何一个解决方案启动并运行。我知道这有点令人沮丧。感谢您提供任何帮助,提示或建议。
答案 0 :(得分:1)
好的,这是一个关于如何运作的简单查询
select stories.*,
IF (views.id is null, 0, 1) as viewed
from stories
left join views
on(views.story_id = stories.id and views.user_id = 1)
where 1
group by stories.id
order by viewed, stories.id
因此,这基本上选择所有故事,使用视图进行连接并将视图限制为user_id,如果视图记录存在设置为已查看,否则设置为未查看,则通过为查看的记录提供较小的索引来对记录进行排序,然后按故事ID排序(例如,您可以将其更改为story.created_at)
现在将其转换为有效的记录查询
Story.select('*', 'IF (views.id is null, 0, 1) as viewed')
.join('left join views on(
views.story_id = stories.id and views.user_id = ?
)', user.id)
.group(:id)
.order(viewed: :asc)
.order(id: :asc)
并将其转换为范围或方法
def as_viewed_by(user)
# same query here
end
这是sql fiddle link你可以检查,3个故事和3个用户
用户1有1个视图,
用户2有2个视图,
用户3有3个视图,
更改@user_id
并查看输出的不同顺序
试试并告诉我它是怎么回事。