67

我正在为库存管理编写 Rails 前端。我希望用户能够注册产品,所以我有:

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

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

问题是产品是在用户注册之前创建的。也就是说,调用Product.create并将其设置为user_id是完全可以接受的nil。但是,正如您可以想象的那样,Rails 不支持开箱即用:

> 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!'

我已经考虑了一堆杂乱无章的解决方法,其中最吸引人的是拥有一个NullUser子类User并使用它来创建产品。但这似乎仍然是一个黑客。这有什么 Rails 方式?

谢谢。


相关迁移:

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

然后:

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

3 回答 3

274

只是 rails 5 的更新,如果你想要这种行为,你需要传递这个选项:

belongs_to :user, optional: true

在 Rails 5 中,每当我们定义belongs_to 关联时,都需要默认存在关联的记录。

更新
如果您仍想默认使用旧行为,您可以将配置添加到您的 application.rb 文件中。

# /config/application.rb
config.active_record.belongs_to_required_by_default = false

注意:具有此配置的 Rails 5 早期版本存在一些问题,但目前已修复,已在候选版本5.2.3上测试。

于 2016-11-30T18:02:37.153 回答
5

Rails 绝对支持这个开箱即用,检查你的迁移,你是否包含了诸如:null => falseuser_id线之类的约束?如果是这样,把它拿出来!

编辑:或者正如@Rodrigo Dias 所说,将其反转为:null => true.

此外,请检查您是否没有对 Product 模型中的用户关系进行任何验证。

于 2013-05-22T19:17:11.693 回答
2

您是否有需要用户在场的验证?如果是这样,请将其删除。

于 2013-05-22T19:24:33.540 回答