Sử dụng nối tiếp Rails để lưu băm vào cơ sở dữ liệu


135

Tôi đang cố gắng lưu id id ánh xạ băm vào một số lần thử trong ứng dụng rails của mình. Di chuyển của tôi đến cơ sở dữ liệu để chứa cột mới này:

class AddMultiWrongToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :multi_wrong, :string
  end

  def self.down
    remove_column :users, :multi_wrong
  end
end

Trong mô hình của tôi, tôi có:

class User < ActiveRecord::Base 
 serialize :multi_wrong, Hash
end

Nhưng khi tôi sử dụng bảng điều khiển rails để kiểm tra điều này bằng cách thực hiện:

user = User.create()
user.multi_wrong = {"test"=>"123"}
user.save

Đầu ra là sai. Có chuyện gì ở đây vậy?


4
Có bất cứ điều gì trong user.errors sau khi cố gắng lưu bản ghi?
Martijn

1
Trong tương lai, bạn có thể sử dụng phương thức bang (lưu!) Để đưa ra một ngoại lệ và hiển thị thông báo lỗi.
leishman

Câu trả lời hay nhất hiện nay sử dụng một ngăn xếp cột JSONoverover.com/a/21397522/1536309
Blair Anderson

Câu trả lời:


174

Các loại cột là sai. Bạn nên sử dụng Văn bản thay vì Chuỗi. Do đó, việc di chuyển của bạn phải là:

 def self.up
   add_column :users, :multi_wrong, :text
 end

Sau đó, Rails sẽ chuyển đổi nó thành YAML cho bạn (và thực hiện tuần tự hóa phù hợp). Các trường chuỗi có giới hạn về kích thước và sẽ chỉ giữ các giá trị đặc biệt nhỏ.


1
@BenjaminTan lý do đằng sau nó là gì, tại sao tôi không thể lưu trữ hàm băm trong kiểu dữ liệu 'chuỗi'.
MV Lohith

8
Bởi vì trong cơ sở dữ liệu, String có độ dài cố định là 255 (tôi nghĩ). Nhưng nếu bạn định tuần tự một hàm băm có kích thước so sánh, thì điều này sẽ dễ dàng vượt quá độ dài. Trường hợp tương tự cho Mảng. Văn bản cho phép độ dài lớn hơn nhiều.
Benjamin Tan Wei Hao

72

CẬP NHẬT:

Việc triển khai chính xác sẽ phụ thuộc vào cơ sở dữ liệu của bạn, nhưng PostgreSQL hiện có jsonjsonbcác cột có thể lưu trữ dữ liệu băm / đối tượng của bạn và cho phép bạn truy vấn JSON bằng ActiveRecord !

thay đổi di chuyển của bạn và bạn đã hoàn tất.

class Migration0001
  def change
    add_column :users, :location_data, :json, default: {}
  end
end

NGUYÊN:

Để biết thêm chi tiết: tài liệu rails && apidock

Hãy chắc chắn rằng cột của bạn là :textvà không:string

Di cư:

$ rails g migration add_location_data_to_users location_data:text

nên tạo:

class Migration0001
  def change
    add_column :users, :location_data, :text
  end
end

Lớp học của bạn sẽ giống như:

class User < ActiveRecord::Base
  serialize :location_data
end

Hoạt động có sẵn:

b = User.new
b.location_data = [1,2,{foot: 3, bart: "noodles"}]
b.save

Tuyệt vời hơn?!

sử dụng hstore postgresql

class AddHstore < ActiveRecord::Migration  
  def up
    enable_extension :hstore
  end

  def down
    disable_extension :hstore
  end
end 

class Migration0001
  def change
    add_column :users, :location_data, :hstore
  end
end

Với hstore bạn có thể đặt thuộc tính trên trường được tuần tự hóa

class User < ActiveRecord::Base  
  # setup hstore
  store_accessor :location_data, :city, :state
end

2
Thật sự tuyệt vời! Cảm ơn!
Alexander Gorg

18

Rails 4 có một tính năng mới gọi là Store , vì vậy bạn có thể dễ dàng sử dụng nó để giải quyết vấn đề của mình. Bạn có thể định nghĩa một trình truy cập cho nó và bạn nên khai báo cột cơ sở dữ liệu được sử dụng cho cửa hàng được tuần tự hóa dưới dạng văn bản, vì vậy có rất nhiều chỗ. Ví dụ ban đầu:

class User < ActiveRecord::Base
  store :settings, accessors: [ :color, :homepage ], coder: JSON
end

u = User.new(color: 'black', homepage: '37signals.com')
u.color                          # Accessor stored attribute
u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor

# There is no difference between strings and symbols for accessing custom attributes
u.settings[:country]  # => 'Denmark'
u.settings['country'] # => 'Denmark'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.