2013-05-22 25 views
27

Tôi đang viết một lối vào Rails để quản lý khoảng không quảng cáo. Tôi muốn người dùng có thể đăng ký sản phẩm, vì vậy tôi có:Rails tùy chọn thuộc về

class User < ActiveRecord::Base 
    has_many :products 
    # <snip> 
end 

class Product < ActiveRecord::Base 
    belongs_to :user 
    # <snip> 
end 

Vấn đề là sản phẩm được tạo ra trước khi được đăng ký bởi một người dùng. Tức là, hoàn toàn có thể chấp nhận để gọi Product.create và chỉ cần đặt số user_id thành nil. Như bạn có thể tưởng tượng, tuy nhiên, Rails không hỗ trợ này ra khỏi hộp:

> Product.create! 
    (0.3ms) SELECT COUNT(*) FROM "products" WHERE "products"."type" IN ('Product') 
    (0.1ms) begin transaction 
    (0.1ms) rollback transaction 
ActiveRecord::RecordInvalid: Validation failed: User can't be blank 
    from ~/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/validations.rb:56:in `save!' 

Tôi đã nghĩ về một loạt các biện pháp khắc phục kludgey, hấp dẫn nhất trong số đó là phải có một NullUser subclassing User và sử dụng để tạo ra sản phẩm. Nhưng điều đó vẫn có vẻ như một hack. Rails Way với điều này là gì?

Cảm ơn.


Việc chuyển có liên quan:

class AddUseridToProducts < ActiveRecord::Migration 
    def change 
    add_column :products, :user_id, :integer 
    end 
end 

và sau:

class Changeuseridtobeoptionalforproducts < ActiveRecord::Migration 
    def change 
    change_column :products, :user_id, :integer, null: true 
    end 
end 
+0

Vui lòng đăng tất cả các xác thực mà bạn có trên mô hình 'Sản phẩm'. –

Trả lời

4

Bạn có xác thực yêu cầu người dùng có mặt không? Nếu vậy, hãy xóa nó.

3

Rails hoàn toàn hỗ trợ này ra khỏi hộp, kiểm tra di cư của bạn, có bạn đã bao gồm một hạn chế như :null => false trên dòng user_id? Nếu có, hãy lấy nó ra!

Chỉnh sửa: Hoặc như trạng thái @Rodrigo Dias, hãy đổi nó thành :null => true.

Ngoài ra, hãy kiểm tra xem bạn không có bất kỳ xác thực nào về mối quan hệ người dùng trong mô hình Sản phẩm hay không.

+1

hoặc chỉ chuyển sang: null => true –

+0

Tôi đã thêm di chuyển của mình vào OP (không dán nó ở đây vì ngắt dòng sẽ chết). – tsm

+0

Tôi đã thực hiện di chuyển với 'change_column: products,: user_id,: integer, null: true', nhưng điều đó không có gì. – tsm

108

Chỉ cần một bản cập nhật cho đường ray 5, nếu bạn muốn loại hành vi, bạn sẽ cần phải vượt qua tùy chọn này:

belongs_to :user, optional: true 

Trong Rails 5, bất cứ khi nào chúng ta định nghĩa một hiệp hội belongs_to, nó là cần thiết để có bản ghi liên quan hiển thị theo mặc định.

+1

Ughhh ... tất cả chúng ta nên đọc ghi chú phát hành ... đúng ? –

+0

Tôi đã thử điều này trong đường ray 5, tôi thấy tùy chọn của nó, nhưng vấn đề là nếu tôi nhập một giá trị không tồn tại trong trường khóa ngoài, nó chấp nhận nó. Trong trường hợp này, nó sẽ làm tăng lỗi rằng nó không có sẵn trong bảng chính. Vậy làm thế nào để sửa lỗi này? –

+0

Bạn thực sự có thể làm điều này với bất kỳ mối quan hệ nào, tôi tin rằng bất cứ điều gì bạn đặt sẽ cố gắng làm một to_i trên nó, nếu nó không phải là một số hoặc không. Bạn nên sử dụng các phương thức thể hiện thuộc tính để cung cấp, việc tạo các liên kết thông qua phương thức này sẽ ngăn chặn các giá trị không chính xác, sử dụng Association.users.build và User.build_association để tránh các bản ghi không tồn tại được liên kết, trong trường hợp của tôi, nơi tôi đang sử dụng tùy chọn true là cho người dùng được liên kết đến một bản ghi nào đó, hồ sơ này thừa nhận người dùng khách vì vậy tôi chỉ làm Association.user = current_user, nếu current_user là không, tôi sẽ không gặp lỗi – Alexis

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