Rails 的可选属性为_to

我正在编写一个 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
62118 次浏览

Rails 完全支持开箱即用,检查您的迁移,是否在 user_id行中包含了像 :null => false这样的约束?如果是这样,把它拿出来!

编辑: 或者按照@Rodrigo Dias 的说法,将其反转为 :null => true

另外,检查在 Product 模型中没有对用户关系进行任何验证。

是否有要求用户在场的验证? 如果有,请删除该验证。

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

belongs_to :user, optional: true

在 Rails 5中,无论何时我们定义一个 properties _ to 关联,默认情况下都需要有关联的记录。

更新
如果默认情况下仍然希望使用旧的行为,可以将配置添加到 application.rb 文件中。

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

注意: 在 Rails 5的早期版本中有一些 问题使用这种配置,但是目前是固定的,在候选版本 5.2.3上测试。