所以三分之二的工作。每次用户阅读文章时,都会创建(has_many通过)历史记录,该记录仅显示"用户在Read_Date_X阅读文章"。
数据库正常,模型正常,历史记录控制器中允许read_date参数,以下操作既有效 1) 检查用户以前是否阅读过文章,2) 创建新的历史记录(如果是第一次阅读本文)。
但是我无法弄清楚为什么中间位(只是更新现有记录上的read_date)不起作用。如果我用 h.save 尝试也没关系!或 h.update()。
h = History.where(article_id: @article, user_id: current_user)
if h.exists?
h = History.where(article_id: @article, user_id: current_user)
h.read_date = Time.now
h.save!
else
h = History.new
h.article_id = @article.id
h.user_id = current_user.id
h.read_date = Time.now
h.save!
end
如果找到现有记录,则引发的错误是:
undefined method `read_date=' for #<History::ActiveRecord_Relation:0x007fe7f30a5e50>
更新:工作答案
所以德里克是对的,这个版本有效。中间位需要一个实例,而不是一个数组,这是顶部条件(没有 .first)正在检查的内容。但是,使用它来返回单个记录意味着您需要在第二部分中将"存在?"交换为"现在?"。
h = History.where(article_id: @article, user_id: current_user).first
if h.present?
h.read_date = Time.now
h.save!
else
h = History.new
h.article_id = @article.id
h.user_id = current_user.id
h.read_date = Time.now
h.save!
end
History.where(article_id: @article, user_id: current_user)
返回一个History::ActiveRecord_Relation
。如果要设置read_date,则需要获取单个记录。
以下是您可以使用当前资源执行此操作的一种方法:
h = History.where(article_id: @article, user_id: current_user).first
处理此问题的另一种方法是使用find_by
而不是where
。这将返回单个记录。喜欢这个:
h = History.find_by(article_id: @article, user_id: current_user)
但是,如果用户有可能为一篇文章拥有许多历史记录,我会坚持您做事的方式并进行一次更改。如果由于某种原因您有很多历史记录,这可能不是很有效。
histories = History.where(article_id: @article, user_id: current_user)
histories.each { |history| history.update(read_date: Time.now) }
我意识到这个问题已经得到了回答。这里有一些额外的想法和建议。
-
我不会有单独的
read_date
属性。只需改用updated_at
即可。它已经在那里为你服务了。而且,您的代码的工作方式、read_date
和updated_at
将始终(本质上)相同。 -
在查找历史记录是否存在时,可以执行
current_user.histories.where(article: @article)
。IMO,这似乎比:History.where(article_id: @article, user_id: current_user).first
更干净。 -
您可以通过检查
h
分配是否成功来避免所有这些exists?
和present?
业务。因此,if h = current_user.histories.where(article: @article)
. -
如果您走 使用
updated_at
而不是read_date
的路线,那么您只需执行h.touch
即可将updated_at
设置为Time.now
。 -
我会使用
has_many :through
提供的<<
方法(而不是手动构建history
记录)。同样,如果使用updated_at
而不是read_date
,则可以使用此方法。
因此,您可以将代码归结为:
if h = current_user.histories.where(article: @article)
h.touch
else
current_user.articles << @article
end
您可以使用三元运算符而不是该if then else
,在这种情况下,它可能看起来像:
current_user.histories.where(article: @article).tap do |h|
h ? h.touch : current_user.articles << @article
end