Rails creating records with timestamps set to nil,

2019-09-02 07:20发布

问题:

I have a Rails 4 application that is showing some odd behavior on the live production site. Often when creating a Post, the default Rails timestamps (created_at and updated_at) are being set to nil, and the only way to solve it is to restart the Heroku dynos.

After I restart Heroku, I can create Posts again. The Post is being created, but its timestamps are simply set to nil. So when I click 'create post', the server throws a 500 error because I have some code in my post view comparing timestamps.

This never happens on my local development environment, only happens on live Heroku server.

Has anyone experienced this? Can it really be an error in the code if it works fine on local and a 'heroku restart' fixes it (temporarily)? My app is dangerously close to memory maxing out, can that have something to do with it?

Here's my Post create definition:

def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id

    @post.user.increment!(:level, 20)

    if @post.save

        Subscription.create(:user_id => current_user.id, :post_id => @post.id, :comments_count => 0, :updated_at => (Time.now - 1.minute))

        User.where(:auto_sub => true).each do |user|
            unless user.id == current_user.id
                Subscription.create(:post_id => @post.id, :user_id => user.id, :comments_count => 0, :updated_at => (Time.now - 1.minute))
            end
        end

        redirect_to @post, notice: "Look at you, you're so good at this internet thing"

    else
        render 'new'
    end
end

And here's my show definition:

def show
    @post = Post.friendly.find(params[:id])
    @user = @post.user
    @other_posts = Post.where(:blog => true).sample(4)

    if user_signed_in?

        @subscription = @post.subscriptions.where(:user_id => current_user.id)

        if @subscription.count > 0
            if @post.comments_count > 0
                @subscription.last.update_attributes(:updated_at => Time.now, :comments_count => @post.comments_count, :last_comment_id => @post.comments.last.id)
            else
                @subscription.last.update_attributes(:updated_at => Time.now, :comments_count => @post.comments_count)
            end
        end

    end

    @comments = @post.comments.paginate(:page => params[:page], :per_page => 20)

    redirect_to live_path if Post.friendly.find(params[:id]).live == true
end

Any ideas what it could be?

回答1:

Setting Post.record_timestamps = false would stop updated_at and created_at being set on all subsequent requests to that dyno (if you have more than one dyno, then requests to other dynos would not be affected until they changed that setting too).

A heroku restart fixes things because in a freshly started app that setting has not been changed - you say you only do this from you upvote and update actions. In development, either those actions rarely run, additionally your development environment reloads automatically in response to code changes.

You don't say why you set record_timestamps to false but you should set it back to true once you've done whatever it is that requires that setting. Personally I would write a method like this :

class Post < ActiveRecord::Base
  def self.without_timestamps
    begin
      old_value = record_timestamps
      self.record_timestamps = false
      yield
    ensure
      self.record_timestamps = old_value
    end
  end
end

And use this to wrap blocks that should run without timestamps.