Reils: autosave seems to work as expected

I did a real basic github project here that demonstrates the problem. Basically, when I create a new comment, it is saved as expected; when I update an existing comment, it is not saved. However, this is not what the docs say for :autosave => true... they say the opposite. Here is the code:

class Post < ActiveRecord::Base
  has_many :comments, 
           :autosave => true, 
           :inverse_of => :post,
           :dependent => :destroy

  def comment=(val)
    obj=comments.find_or_initialize_by(:posted_at=>Date.today)
    obj.text=val
  end
end

class Comment < ActiveRecord::Base
  belongs_to :post, :inverse_of=>:comments
end

Now in the console I am testing:

p=Post.create(:name=>'How to groom your unicorn')
p.comment="That cool!"
p.save!
p.comments # returns value as expected. Now we try the update case ... 

p.comment="But how to you polish the rainbow?"
p.save!
p.comments # oops ... it wasn't updated

Why not? What am I missing?

Please note that if you do not use "find_or_initialize", it works in the same way that ActiveRecord respects the association cache, otherwise it reloads comments too often, throwing changes. those. this implementation works

def comment=(val)
  obj=comments.detect {|obj| obj.posted_at==Date.today}
  obj = comments.build(:posted_at=>Date.today) if(obj.nil?)
  obj.text=val
end

, , , . , , , .

+4
3

. , find_or_initialize_by , .

def comment=(val)
  obj=comments.find_or_initialize_by(:posted_at=>Date.today)
  unless obj.new_record?
    association(:comments).add_to_target(obj) 
  end
  obj.text=val
end
+2

, . find_or_initialize_by, , - . , .

:

  def comment=(val)
    obj = comments.find_or_initialize_by(:posted_at => Date.today)
    obj.text = val
    puts "obj.object_id: #{obj.object_id} (#{obj.text})"
    puts "comments[0].object_id: #{comments[0].object_id} (#{comments[0].text})"
    obj.text
  end

:

p.comment="But how to you polish the rainbow?"
obj.object_id: 70287116773300 (But how to you polish the rainbow?)
comments[0].object_id: 70287100595240 (That cool!)

, find_or_initialize_by , . , , , , :

  def comment=(val)
    obj = comments.detect {|c| c.posted_at == Date.today } || comments.build(:posted_at => Date.today)
    obj.text = val
  end
+1
John Negle is right. But you can still do what you want without using it detect. Since you are updating only today's commentary, you can order an association posted_dateand simply access the first member of the collection commentsto update it. Rails will be automatically debugged from you:
class Post < ActiveRecord::Base
  has_many :comments, ->{order "posted_at DESC"}, :autosave=>true,     :inverse_of=>:post,:dependent=>:destroy

  def comment=(val)
    if comments.empty? || comments[0].posted_at != Date.today
      comments.build(:posted_at=>Date.today, :text => val)
    else
      comments[0].text=val
    end
  end
end
0
source

Source: https://habr.com/ru/post/1621639/


All Articles