簡體   English   中英

Rails:通過控制器通過記錄更新現有的has_many嗎?

[英]Rails: update existing has_many through record via controller?

因此,這項工作的三分之二。 每次用戶閱讀文章時,都會創建一條歷史記錄(has_many至),該記錄僅顯示“用戶在Read_Date_X處閱讀了文章”。

數據庫正常,模型正常,History控制器中允許使用read_date參數,並且以下操作都可以進行以下操作:1)檢查用戶之前是否閱讀過文章;以及2)創建新的History記錄(如果是)第一次在這篇文章上。

但是我無法弄清楚為什么中間位(僅更新現有記錄的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)正在檢查的內容。 但是,使用該記錄返回單個記錄意味着您需要交換“存在”? 展示?” 在第二部分。

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_dateupdated_at將始終(基本上)相同。

  • 在查詢歷史記錄是否存在時,可以執行current_user.histories.where(article: @article) IMO,似乎比以下代碼更干凈: History.where(article_id: @article, user_id: current_user).first

  • 您可以避免所有exists?事情exists? present? 只需檢查h分配是否成功即可開展業務。 因此, if h = current_user.histories.where(article: @article)

  • 如果你使用的路線updated_at而不是read_date ,那么你可以設置updated_atTime.now通過簡單地做h.touch

  • 我將使用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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM