Rails:通过控制器记录更新现有 has_many?
Rails: update existing has_many through record via controller?
所以这三分之二的作品。每次用户阅读文章时,都会创建一条历史记录(has_many 到),它只是说 "User read Article at 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>
更新:有效答案
所以 Derek 是对的,这个版本有效。中间位需要单个实例,而不是数组,这是顶部条件(没有 .first)正在检查的内容。但是,将其用于 return 单个记录意味着您需要在第二部分将 "exists?" 交换为 "present?"。
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)
是 return 一个 History::ActiveRecord_Relation
。如果要设置 read_date,则需要获取一条记录。
这是您可以使用现有资源执行此操作的一种方法:
h = History.where(article_id: @article, user_id: current_user).first
另一种处理此问题的方法是使用 find_by
而不是 where
。这将 return 一条记录。像这样:
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
,那么您只需执行 [=] 即可将 updated_at
设置为 Time.now
26=].
我会使用 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
所以这三分之二的作品。每次用户阅读文章时,都会创建一条历史记录(has_many 到),它只是说 "User read Article at 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>
更新:有效答案
所以 Derek 是对的,这个版本有效。中间位需要单个实例,而不是数组,这是顶部条件(没有 .first)正在检查的内容。但是,将其用于 return 单个记录意味着您需要在第二部分将 "exists?" 交换为 "present?"。
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)
是 return 一个 History::ActiveRecord_Relation
。如果要设置 read_date,则需要获取一条记录。
这是您可以使用现有资源执行此操作的一种方法:
h = History.where(article_id: @article, user_id: current_user).first
另一种处理此问题的方法是使用 find_by
而不是 where
。这将 return 一条记录。像这样:
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
,那么您只需执行 [=] 即可将updated_at
设置为Time.now
26=].我会使用
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