ActiveRecord不知道时区吗?

时间:2018-12-04 02:14:55

标签: ruby-on-rails ruby timezone utc

我对时区有一个疑问

我已经完成了以下操作,当我执行以下查询时,我的活动记录仍与时区不匹配

def stock_by_date(date)
   UserStock.where("date(created_at) = ? and user_id = ? ", date , current_user.id)
end

我在application.rb旁边做了以下操作

config.active_record.default_timezone = :utc
config.active_record.time_zone_aware_attributes = true
config.beginning_of_week = :sunday
config.active_record.time_zone_aware_types = [:datetime, :time]

我在注册方法中添加了时区字段,它可以正确显示当前时区,但是当我为当前时区添加股票时,它会显示在当前时区的前一天或后一天当我添加库存时,时间戳是在查看Rails控制台之前的一天

我的schema.rb

ActiveRecord::Schema.define(version: 2018_11_28_183416) do

  create_table "friendships", force: :cascade do |t|
    t.integer "user_id"
    t.integer "friend_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["friend_id"], name: "index_friendships_on_friend_id"
    t.index ["user_id"], name: "index_friendships_on_user_id"
  end

  create_table "notes", force: :cascade do |t|
    t.string "content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "user_id"
    t.index ["user_id"], name: "index_notes_on_user_id"
  end

  create_table "stocks", force: :cascade do |t|
    t.string "ticker"
    t.string "name"
    t.decimal "last_price"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "user_stocks", force: :cascade do |t|
    t.integer "user_id"
    t.integer "stock_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["stock_id"], name: "index_user_stocks_on_stock_id"
    t.index ["user_id"], name: "index_user_stocks_on_user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "first_name"
    t.string "last_name"
    t.string "time_zone", default: "UTC"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

end

例如enter image description here enter image description here

如何解决此问题?

注意:如果需要更多信息,请告诉我

注意:为简洁起见,这是我的repo

注意:我的配置完全没有显示出可靠的行为,而且我很困惑:/和我有同样的问题需要注意

---- 更新 -------------------

在我的Rails控制台中

enter image description here

2 个答案:

答案 0 :(得分:1)

您是否通过指定范围来尝试查询?

因为您要查找某个日期创建的user_stocks。但是请注意,created_at是一个datetime对象,我猜您的date变量可能只是一个date对象。

def stock_by_date(date)
  UserStock.where(created_at: date.midnight..date.end_of_day, user_id: current_user.id)
end

答案 1 :(得分:1)

使用此内容创建迁移,以删除默认值created_at,因此默认情况下不会在数据库级别填充该值。

change_column_default(:user_stocks, :created_at, nil)

此后,在创建新的UserStock时,需要指定created_at值,然后在其中可以指定带用户日期的created_at,并注意时区。

UserStock.create(created_at: Time.now.in_time_zone(user.time_zone).to_time...)

或者您也可以将其添加到模型的回调中,这样,每次创建UserStock时它都会自动执行,它会更改值

class UserStock < ActiveRecord::Base
  before_create :set_created_at

  private
    def set_created_at
      self.created_at = time.now.in_time_zone(self.user.time_zone).to_time
    end
end

因此,每次创建一个时,该值都是正确的。这样它可能会按预期工作。

另一种选择,如果您不仅仅需要特定的模型并将其用于所有用户交互,则可以在应用程序控制器上创建一个before过滤器,以动态设置时区,例如

class ApplicationController < ActionController::Base
  before_filter :set_time_zone

  def set_time_zone(&block)
    time_zone = current_user.try(:time_zone) || 'UTC'
    Time.use_zone(time_zone, &block)
  end
end