NullVoxPopuli
NullVoxPopuli

Reputation: 65123

ActiveRecord not updating / saving, but shows the field has been modified in the console (db says otherwise)

content = Content.find(params[:content_id])
content.body.insert(start_index, span_open)
content.save!
content.body.insert(end_index + span_open.length, span_open)
content.save!

puts "=========================================="
c = Content.find(params[:content_id])
puts c.body

so the above is what I've been trying to do. lots of saves.. it should save right?

in the console I see

===========================================
le modified text (body attr) here

I'm inserting span's into text, and in the console (above) it shows the changes successful in the puts statement. But when I rerender the page, everything is back the way it was (inspect element shows no spans)

One thing that I find weird is that the puts statement executes before the

"Processing NameOfController#action (for ....)" 

with all the DB calls and such. I scroll down to where Content.find would be (it's there twice, so this is easy) and I see this:

SHOW FIELDS FROM `contents`
  Content Load (1.6ms)   SELECT * FROM `contents` WHERE (`contents`.`id` = 328) 
  SQL (0.2ms)   BEGIN
  SQL (0.1ms)   COMMIT
  SQL (0.1ms)   BEGIN
  SQL (0.2ms)   COMMIT
  CACHE (0.0ms)   SELECT * FROM `contents` WHERE (`contents`.`id` = 328) 
  SQL (0.1ms)   BEGIN
  SQL (0.1ms)   COMMIT

Now, it says that it's loading the second call from cache... what's up with that? since I've changed it since the last .find()?

I'm using Ruby on Rails 2.3.8

UPDATE: incorporating Dan Seaver's suggestions:

  content = Content.uncached_find(params[:content_id])
  content.body = content.body.insert(start_index, span_open)
  content.save!
  content.body = content.body.insert(end_index + span_open.length, span_close)
  content.save!
  a = content.body
# ActiveRecord::Base.connection.update("
#      UPDATE `contents`
#      SET body = '#{content.body}'
#      WHERE id = #{params[:content_id]}")
puts "=========================================="
content = Content.uncached_find(params[:content_id])
  puts (a == content.body).inspect

output / terminal:

==========================================
false

Content Load (1.5ms)   SELECT * FROM `contents` WHERE (`contents`.`id` = 351) 
  SQL (0.1ms)   BEGIN
  SQL (0.1ms)   COMMIT
  SQL (0.1ms)   BEGIN
  SQL (0.2ms)   COMMIT
  Content Load (0.3ms)   SELECT * FROM `contents` WHERE (`contents`.`id` = 351) 

Upvotes: 3

Views: 6748

Answers (2)

Dan McClain
Dan McClain

Reputation: 11920

The way that Rails SQL Caching works is that queries are cached within an action:

However, it’s important to note that query caches are created at the start of an action and destroyed at the end of that action and thus persist only for the duration of the action. If you’d like to store query results in a more persistent fashion, you can in Rails by using low level caching.

This article describes how you can avoid the cache with the following

Update Not having previously used uncached, it seems like is defined within active record, so you will have to add a class method to content like the following:

def self.uncached_find(content_id)
  uncached do 
    find(content_id)
  end 
end

Then use Content.uncached_find(params[:content_id]) (documentation) where you would use Content.find

Update 2 I see the issue now!! You aren't actually modifying anything. String#insert returns a modified string, it does not modify content.body in place, you need to do the following:

content.body = content.body.insert(start_index, span_open)

Try the above line with your save, and it should work

Upvotes: 4

NullVoxPopuli
NullVoxPopuli

Reputation: 65123

to force updating:

ActiveRecord::Base.connection.update("
  UPDATE `contents`
  SET body = '#{content.body}'
  WHERE id = #{params[:content_id]}")

Upvotes: 0

Related Questions