0

I have my app setup to run ajax when a video is done watching. The ajax calls a User#action below. The problem is, when it is first run, it works and adds {"timestamp"=>"1"} but it never updates to {"timestamp"=>"1,1"}. Is there something I am missing? Can I not update the value in an hstore hash?

# Increases User's workouts after video is watched
    def increase_workouts
      @user = current_user
      if logged_in?
        if @user.newworkouts[Time.now.strftime("%Y%m%d").to_sym] == nil
          @user.newworkouts[Time.now.strftime("%Y%m%d").to_sym] = "0"
        end
        @user.newworkouts[Time.now.strftime("%Y%m%d").to_sym] += "," + "1"
        @user.save
        render(json: { message: "Workouts increased" }, status: :ok) and return
      else 
        render(json: { message: "Workouts increased" }, status: :ok) and return
      end
    end
mu is too short
  • 426,620
  • 70
  • 833
  • 800
Doughtz
  • 359
  • 2
  • 12

1 Answers1

0

I think ActiveRecord isn't realizing that you've changed newworkouts. If you do this:

h = { }
h[:k] = 6

or this:

h = { :k => 11 }
h[:k] = 6

then h itself hasn't actually changed, its contents have changed but h.object_id is the same before h[:k] = 6 as it is after. Similar things can happen with PostgreSQL array columns and ActiveRecord so hstore suffering similar issues wouldn't be surprising.

The solutions should be the same as with arrays:

  1. Really change the hash.

    w = @user.newworkouts.dup
    # update `w` as needed...
    @user.newworkouts = w # Replace the reference
    @user.save
    
  2. Manually mark it as dirty.

    # Update @user.newworkouts as you are now...
    @user.newworkouts_will_change! # Mark it as dirty.
    @user.save
    

I'd also recommend burying that login in a method on your model, then you could just say @user.add_workout_at(Time.now) in your controller and not have to worry about the ugly details of the internal representation.

You might also want to switch from hstore to jsonb for this column, then you could use an array as the value ({"timestamp": [0,1]}) rather than some sort of CSV-in-a-string like you're currently doing.

Community
  • 1
  • 1
mu is too short
  • 426,620
  • 70
  • 833
  • 800