2009-10-16 45 views
78

Hãy xem xét kịch bản tạo bảng dưới đây:Làm cách nào để đặt giá trị mặc định cho cột ngày giờ trong tập lệnh di chuyển?

create_table :foo do |t| 
    t.datetime :starts_at, :null => false 
end 

là nó có thể thiết lập giá trị mặc định như thời điểm hiện tại?

Tôi đang cố gắng tìm một DB tương đương độc lập ở đường ray cho các định nghĩa cột SQL đưa ra dưới đây:

Oracle Cú pháp

start_at DATE DEFAULT SYSDATE() 

MySQL Cú pháp

start_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 

HOẶC

start_at DATETIME DEFAULT NOW() 

Trả lời

109

Bạn có thể thêm một chức năng trong một mô hình như thế này:

before_create :set_foo_to_now 
    def set_foo_to_now 
    self.foo = Time.now 
    end 

Vì vậy mà mô hình sẽ đặt thời gian hiện tại trong mô hình.

Bạn cũng có thể đặt một đoạn mã sql trong việc di chuyển cho thiết lập các giá trị mặc định ở cấp cơ sở dữ liệu, một cái gì đó như:

execute 'alter table foo alter column starts_at set default now()' 

Thiết một cái gì đó như thế này:

create_table :foo do |t| 
    t.datetime :starts_at, :null => false, :default => Time.now 
end 

nguyên nhân thực hiện Thời gian .now chức năng trong quá trình di chuyển để bảng trong cơ sở dữ liệu được tạo như sau:

create table foo (starts_at timestamp not null default '2009-01-01 00:00:00'); 

nhưng tôi nghĩ rằng đó không phải là những gì bạn muốn.

+1

Hiện tại tôi đang đặt giá trị trong: before_create callback.
Tôi đang tìm kiếm một loại ma thuật AR ở đây. Tôi đã dành một chút thời gian để xem mã Rails, nhưng tôi không tìm thấy bất kỳ giải pháp nào. Tôi nghĩ rằng tôi sẽ hỏi xung quanh để xem nếu có bất kỳ lựa chọn thay thế. –

+0

Tôi khuyên bạn nên làm điều đó với một cuộc gọi lại trên before_create. – jonnii

+1

Tôi không muốn thay đổi bảng DB vì tôi muốn giữ mã DB trung lập. Tôi đã hy vọng rằng AR có một số cơ chế để thiết lập giá trị mặc định cho trường Datetime tương tự như trường created_at. –

12

Nếu bạn có cột ngày giờ được gọi là created_at hoặc created_on, ActiveRecord sẽ 'kỳ diệu' đặt giá trị này thành ngày giờ tạo. Bạn không cần phải làm bất cứ điều gì khác ngoại trừ để có cột đó.

Bạn cũng có thể có updated_at hoặc updated_on và nó sẽ được cập nhật khi bản ghi được cập nhật.

+0

Tôi đã có các trường đó trong bảng của mình. Tôi cần một trường bổ sung cho trình lên lịch để giữ ngày bắt đầu. Hiện tại, tôi đang sử dụng: before_create gọi lại để đặt ngày hiện tại. Nếu tôi gặp phải tình huống này thường xuyên, tôi phải viết một plugin để thay đổi xử lý giá trị mặc định trong phương thức 'to_sql' của lớp ColumnDefinition. –

9

Tôi đã tìm kiếm một giải pháp tương tự nhưng tôi đã kết thúc bằng cách sử dụng https://github.com/FooBarWidget/default_value_for.

Plugin default_value_for cho phép người dùng xác định giá trị mặc định cho mô hình ActiveRecord theo cách khai báo. Ví dụ:

class User < ActiveRecord::Base 
    default_value_for :name, "(no name)" 
    default_value_for :last_seen do 
    Time.now 
    end 
end 

u = User.new 
u.name  # => "(no name)" 
u.last_seen # => Mon Sep 22 17:28:38 +0200 2008 
-1

Trong câu trả lời được đưa ra bởi @ szymon-lipiński (Szymon Lipiński), phương pháp thực thi không hoạt động đối với tôi. Nó đã ném một lỗi cú pháp MySQL.

Cú pháp MySQL làm việc cho tôi chính là điều này.

execute "ALTER TABLE mytable CHANGE `column_name` `column_name` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" 

Vì vậy, để thiết lập giá trị mặc định cho một cột datetime trong kịch bản chuyển thể được thực hiện như sau:

def up 
    create_table :foo do |t| 
    t.datetime :starts_at, :null => false 
    end 

    execute "ALTER TABLE `foo` CHANGE `starts_at` `starts_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" 
end 
7

tôi thường làm:

def change 
    execute(" 
    ALTER TABLE your_table 
    ALTER COLUMN your_column 
    SET DEFAULT CURRENT_TIMESTAMP 
    ") 
end 

Vì vậy, bạn schema.rb đang diễn ra để có một cái gì đó như:

create_table "your_table", force: :cascade do |t| 
    t.datetime "your_column", default: "now()" 
end 
+0

Nhược điểm: giải pháp này chỉ hoạt động khi bạn chạy 'rake db: migrate', không phải khi bạn tải tệp lược đồ của mình bằng một cái gì đó như' rake db: schema: load'. –

82

này được hỗ trợ bây giờ trong Rails 5.

Đây là một sự chuyển đổi mẫu:

class CreatePosts < ActiveRecord::Migration[5.0] 
    def change 
    create_table :posts do |t| 
     t.datetime :modified_at, default: -> { 'CURRENT_TIMESTAMP' } 
     t.timestamps 
    end 
    end 
end 

thảo luận Xem tại https://github.com/rails/rails/issues/27077 và trả lời đó bằng prathamesh-sonpatki

+6

+10000 đây là câu trả lời phù hợp hơn hiện nay. – hcarreras

+5

Câu trả lời hay. Hoàn toàn là một bên, hãy lưu ý rằng trong Postgres 'CURRENT_TIMESTAMP' sẽ là thời điểm bắt đầu giao dịch hiện tại, vì vậy nhiều bản ghi được tạo trong cùng một giao dịch sẽ nhận được cùng một giá trị đó. Nếu bạn muốn thời gian hiện tại thực tế câu lệnh thực thi (bỏ qua ngữ cảnh giao dịch), hãy kiểm tra 'CLOCK_TIMESTAMP'. –

-1

Nếu bạn cần phải thay đổi một Cột DateTime hiện tại trong Rails 5 (thay vì tạo bảng mới như được chỉ định trong các câu trả lời khác) để có thể tận dụng khả năng ngày mặc định, bạn có thể tạo di chuyển như sau:

class MakeStartsAtDefaultDateForFoo < ActiveRecord::Migration[5.0] 
    def change 
    change_column :foos, :starts_at, :datetime, default: -> { 'CURRENT_TIMESTAMP' } 
    end 
end 
+0

Biểu mẫu không hợp lệ để bỏ phiếu điều gì đó và không giải thích vấn đề đã được thực hiện với câu trả lời. Bất cứ ai có một ý tưởng tại sao điều này đã được bỏ phiếu xuống? Nó hiển thị cú pháp nếu bạn muốn thay đổi một cột thay vì tạo một cột. –

+0

Tôi không phải là người đã xuống hạng, nhưng tôi gặp khó khăn khi thấy câu trả lời này khác với câu trả lời của bạn sẽ ra sao trước một năm.Câu hỏi đặt ra là thiết lập mặc định và câu trả lời của bạn có cùng một mệnh đề lambda. – nurettin

+0

@nurettin Tôi nhận được quan điểm của bạn, nhưng trong phòng thủ của tôi, cú pháp cho ** tạo ** một cột mới là khác nhau một cách tinh tế từ ** thay đổi ** một cột hiện có. Cung cấp cú pháp đó cho những người đã tìm thấy câu hỏi này thông qua tìm kiếm trên web trong khi cố gắng thêm mặc định vào mô hình dữ liệu hiện tại của họ thay vì tạo mô hình/bảng mới hoàn toàn có thể hữu ích. Không? Bạn đang giả sử mọi người đều biết họ có thể sử dụng cùng một lambda cho một sự thay đổi_column. Có lẽ họ nên nhận ra điều đó, nhưng đó là lý do tại sao tôi trả lời ở đây - vì vậy họ không phải đi đâu khác để tìm ra điều đó. Chúc mừng! –

Các vấn đề liên quan