Как я могу установить значение по умолчанию для даты в Rails 5.2 с помощью Postgres?

Использование Rails 5.2 и Postgres 9.6.8

У меня есть поле даты, которое я хочу хранить отдельно от created_at и updated_at, потому что меня не волнует время или даже день. Я действительно просто хочу сохранить месяц и год.

Мне любопытно, есть ли способ сделать это и указать значение по умолчанию.

Исследуя этот вопрос, я увидел ответы, предлагающие:

t.date :month_and_year, null: false, default: -> { 'NOW()' }

но это не работает. Я пытался изменить столбец на прямой datetime, но мне так и не удалось установить значение по умолчанию.

Полагаю, я мог бы хранить месяц и год отдельно как целые числа, но мне любопытно, придумал ли кто-нибудь хорошее решение для этого.

проверьте эту статью - bencurtis.com/2014/02/…

Sampat Badhe 09.09.2018 06:30

этот синтаксис кажется устаревшим. Кроме того, я обнаружил, что он действительно сохраняет дату, но мне всегда приходится вызывать .reload в экземпляре, чтобы получить значение обратно из БД.

Jared Rader 09.09.2018 06:35

Еще один способ, который работает без перезагрузки, - это назначить текущую дату полю в обратном вызове before_save.

Sampat Badhe 09.09.2018 06:40

@SampatBadhe Обратной стороной этого является то, что вы не получите значение по умолчанию, когда выполните обычный метод @m = Model.new в методе контроллера def new.

mu is too short 09.09.2018 07:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
998
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Параметр :default становится частью определения таблицы в базе данных. Итак, это:

t.date :month_and_year, null: false, default: -> { 'NOW()' }

становится SQL следующим образом:

create table ... (
  ...
  month_and_year date not null default now(),
  ...
)

ActiveRecord будет использовать значения по умолчанию из таблицы если, которую он может понять. Если у вас простое значение по умолчанию, подобное этому:

some_column integer default 6

то ActiveRecord будет использовать это значение по умолчанию, потому что он знает, что такое 6 и как с ним работать.

В вашем случае значение по умолчанию в базе данных - это вызов функции базы данных now(), но AR не знает, что означает now(), поэтому не устанавливает значение по умолчанию во вновь созданной модели. Когда эта модель будет сохранена в базе данных, month_and_year не будет, поэтому база данных будет использовать значение по умолчанию для столбца month_and_year в новой строке; конечно, ActiveRecord ничего об этом не знает, поэтому вам нужно вызвать reload, чтобы получить значение month_and_year из базы данных.

Как можно это решить? Вы можете использовать хук after_initialize следующим образом:

after_initialize if: :new_record? do
  if (month_and_year.nil?)
    self.month_and_year = Date.today
  end
end

Я достаточно занимаюсь подобными вещами, поэтому у меня возникла простая проблема:

module RecordDefaults
  extend ActiveSupport::Concern

  module ClassMethods
    #
    # Examples:
    #
    #     use_defaults number: 6,
    #                  %i[time1 time2] => Time.method(:now),
    #                  array: [6, 11, 23, 42]
    #
    def use_defaults(defs)
      after_initialize if: :new_record? do
        defs.each do |attrs, value|
          if (value.respond_to?(:call))
            value = instance_exec(&value)
          else
            value = value.dup
          end
          attrs_without_values = ->(a) { send(a).nil? }
          use_the_default      = ->(a) { send("#{a} = ", value) }
          Array(attrs).select(&attrs_without_values).each(&use_the_default)
        end
      end
    end
  end
end

а потом:

class SomeModel < ApplicationRecord
  include RecordDefaults
  use_defaults month_and_year: Date.method(:today)
end
Ответ принят как подходящий

Я согласен с тем, что му слишком короткий сказано в его ответе. Но я хотел бы добавить здесь, что есть способ настроить его в ActiveRecord с помощью его нового attribute API.

Например, если у вас есть столбец month_and_year внутри модели Post, и вы хотите установить для него значение по умолчанию, вы можете написать это, как показано ниже:

class Post < ApplicationRecord
  attribute :month_and_year, :date, default: -> { Date.today }
end

Вышеуказанное установит для вас дату по умолчанию. См. Пример:

Loading development environment (Rails 5.2.1)
2.5.1 :001 > post = Post.new(name: 'Post A', title: 'Post title', content: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.')
 => #<Post id: nil, name: "Post A", title: "Post title", content: "Lorem Ipsum is simply dummy text of the printing a...", created_at: nil, updated_at: nil, month_and_year: "2018-09-09">
2.5.1 :002 > post.save
   (0.2ms)  BEGIN
  Post Create (0.8ms)  INSERT INTO "posts" ("name", "title", "content", "created_at", "updated_at", "month_and_year") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["name", "Post A"], ["title", "Post title"], ["content", "Lorem Ipsum is simply dummy text of the printing and typesetting industry."], ["created_at", "2018-09-09 09:52:57.262764"], ["updated_at", "2018-09-09 09:52:57.262764"], ["month_and_year", "2018-09-09"]]
   (2.0ms)  COMMIT
 => true
2.5.1 :003 > Post.last
  Post Load (0.5ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT $1  [["LIMIT", 1]]
 => #<Post id: 3, name: "Post A", title: "Post title", content: "Lorem Ipsum is simply dummy text of the printing a...", created_at: "2018-09-09 09:52:57", updated_at:"2018-09-09 09:52:57", month_and_year: "2018-09-09">
2.5.1 :004 >

Другие вопросы по теме