2015-05-27 14 views
6

Trong Ruby on Rails, một mô hình với trường mảng được tuần tự hóa sẽ không cập nhật trên .save() nếu mảng trống, nơi mà trước đó nó có dữ liệu.Không thể lưu mảng trống vào cơ sở dữ liệu khi được tuần tự

Tôi đang sử dụng:

  • của Ruby 2.2.1
  • Rails 4.2.1
  • sqlite3 1.3.10

    Tôi tạo ra một mô hình mới với một lĩnh vực thiết lập dưới dạng văn bản:

    đường ray g model Tên người dùng: chuỗi ví dụ: văn bản

Trong tập tin User.rb Tôi nói thêm:

serialize :example, Array 

tôi instantiated một trường hợp mới của lớp User:

test = User.new 
<User id: nil, name: nil, example: [], created_at: nil, updated_at: nil> 

Sau đó, tôi tiết kiệm cho người sử dụng để đảm bảo nó tiết kiệm một cách chính xác:

test.save() 
(0.1ms) begin transaction 
SQL (0.4ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-05-27 16:17:31.902342"], ["updated_at", "2015-05-27 16:17:31.902342"]] 
(0.7ms) commit transaction 
=> true 

Và thêm một số dữ liệu để cảm thấy vui vẻ và có mục đích:

test.example.push(1) 
test.example.push(2) 

Và lưu nó lên:

test.save() 
(0.1ms) begin transaction 
SQL (0.3ms) UPDATE "users" SET "example" = ?, "updated_at" = ? WHERE "users"."id" = ? [["example", "---\n- 1\n- 2\n"], ["updated_at", "2015-05-27 16:17:50.331777"], ["id", 1]] 
(0.8ms) commit transaction 
=> true 

Và chắc chắn mọi thứ được lưu độc đáo:

test 
<User id: 1, name: nil, example: [1, 2], created_at: "2015-05-27 16:17:31", updated_at: "2015-05-27 16:17:50"> 

Tôi đã xóa một mục, xác minh nó đã bị xóa, và lưu nó, làm cho chắc chắn rằng SQL đầu ra hiển thị UPDATE:

test.example.delete(1) 
=> 1 
test 
<User id: 1, name: nil, example: [2], created_at: "2015-05-27  16:17:31", updated_at: "2015-05-27 16:17:50"> 
test.save() 
(0.1ms) begin transaction 
SQL (0.9ms) UPDATE "users" SET "example" = ?, "updated_at" = ? WHERE "users"."id" = ? [["example", "---\n- 2\n"], ["updated_at", "2015-05-27 16:18:30.148553"], ["id", 1]] 
(8.9ms) commit transaction 
=> true 

Tôi đã xóa phần dữ liệu cuối cùng khỏi rray, mảng trống đã được xác minh và lưu nó. Lưu ý việc thiếu hành động UPDATE và trả về đúng:

test.example.delete(2) 
=> 2 
test 
<User id: 1, name: nil, example: [], created_at: "2015-05-27 16:17:31", updated_at: "2015-05-27 16:18:30"> 
test.save() 
(0.1ms) begin transaction 
(0.1ms) commit transaction 
=> true 

Nhiều lần lưu có cùng kết quả. Một đối tượng tài khoản mới vẫn có mảnh cuối cùng của dữ liệu trong nó:

test = User.find(1) 
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]] 
<User id: 1, name: nil, example: [2], created_at: "2015-05-27 16:17:31", updated_at: "2015-05-27 16:18:30"> 

Một cách giải quyết là loại bỏ những "mảng" từ dòng serialize trong mô hình khởi sân khi nil. Nhưng điều này có nghĩa là lần đầu tiên tôi thêm dữ liệu vào một cá thể mới, tôi phải đặt trường theo cách thủ công thành một mảng trống (test.example = []) để gọi .push() trên đó. Tất cả mọi thứ hoạt động tốt trong thiết lập này, và mảng mới làm trống tiết kiệm hạnh phúc cho DB.

tôi thấy một vấn đề khép kín trên Rails Github chỉ ra rằng cột serialized luôn nên được lưu, nhưng không có ý tưởng nếu điều này là thích hợp:

https://github.com/rails/rails/issues/8328

tôi không thể phân biệt bất cứ điều gì từ mã nguồn serialize mà có thể thắp sáng cho tôi:

http://apidock.com/rails/ActiveModel/Serializers/Xml/Serializer/serialize

tại sao thêm "mảng" ở cuối dòng nguyên nhân sắp đặt từng mảng trống để không được lưu vào cơ sở dữ liệu ?

+1

Chào mừng bạn đến với Stack Overflow. Dưới đây là một số mẹo để viết câu hỏi: Đừng tack on "Ruby on Rails" hoặc các thẻ tương tự. Stack Overflow (và công cụ tìm kiếm) sử dụng các thẻ bạn đã xác định cho câu hỏi. Thay vào đó chỉ cần viết một câu mô tả ngắn. Trong cơ thể, không cần sử dụng các tiêu đề. Thay vào đó, viết bình thường, như bạn sẽ làm khi viết cho một đồng nghiệp. Stack Overflow giống như một bách khoa toàn thư về lập trình Q & A nhưng với một phong cách ít chính thức hơn. Mô phỏng phong cách của các câu hỏi khác để duy trì giao diện chung. Cũng tìm hiểu định dạng mã nội tuyến. –

+0

Cảm ơn lời khuyên và chỉnh sửa! Tôi sẽ lưu ý lời khuyên này cho các yêu cầu trong tương lai. Bạn có thể xây dựng trên định dạng mã nội tuyến không? Tôi đã sử dụng giao diện điều khiển đầu ra cho bài viết của tôi bởi vì tôi nghĩ rằng nó tốt nhất giới thiệu vấn đề. – hsidar

Trả lời

1

SQLite không hỗ trợ loại cột Array. Tôi nghĩ điều gì đang xảy ra là khi bạn cố gắng lưu Người dùng bằng một mảng trống cho thuộc tính ví dụ, nó được hiểu là không có thay đổi đối với cột ví dụ. Điều gì sẽ xảy ra nếu bạn thử điều này sau khi bạn tạo người dùng thử nghiệm với dữ liệu mẫu?

test.example = nil 
test.save 

Ngoài ra, điều gì xảy ra với điều này?

test.example = [nil] 
test.save 

Nó có vẻ như là giải pháp sẽ được sử dụng một ActiveRecord callback như before_save để kiểm tra thuộc tính ví dụ mô hình sử dụng để xác định xem nó là một mảng trống. Nếu có, hãy đặt thuộc tính thành nil hoặc [nil] (tùy theo công trình nào) và sau đó dữ liệu sẽ vẫn tồn tại tương ứng.

+0

Cài đặt và lưu chỉ vì không hoạt động miễn là nó không cố gắng lưu mảng trống trước tiên. Giải pháp [nil] cũng được lưu, nhưng để lại mọi cuộc gọi .length trở về 1 không tối ưu. Hy vọng chính của tôi ở đây là để tìm ra lý do tại sao thêm Array vào dòng serialize bất hợp pháp hành vi khác nhau trên một lưu trống hơn nếu nó không có. Giải pháp thay thế hiện tại của tôi là chỉ sử dụng Serialize, sans Array và sau đó kiểm tra 'nil' khi phương thức tạo được gọi là: 'test.example = [] if! Test.example' – hsidar

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