【问题标题】:Rails optional belongs_toRails 可选的 belongs_to
【发布时间】:2013-05-17 23:36:21
【问题描述】:

我正在为库存管理编写 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

【问题讨论】:

  • 请发布您对Product 模型的所有验证。

标签: ruby-on-rails ruby activerecord


【解决方案1】:

只是 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 的早期版本中有一些 issues,但目前已修复,在候选版本 5.2 上进行了测试。 3.

【讨论】:

  • 我在 rails 5 中试过这个,我看到它是可选的,但问题是如果我在外键字段中输入一个不存在的值,它会接受它。在这种情况下,它应该引发错误,即它在主表中不可用。那么如何解决这个问题呢?
  • 您实际上可以对任何关系执行此操作,我相信您放置的任何内容都会尝试对其执行 to_i ,如果它不是数字或零。您应该使用belong_to提供的实例方法,通过此方法创建关联将防止不正确的值,使用 Association.users.build 和 User.build_association 来避免不存在的记录被关联,在我的情况下,我正在使用可选 true 用于关联用户到某个记录,该记录允许访客用户,所以我只是在做 Association.user = current_user,如果 current_user 为 nil 我不会收到错误
  • 6.0.3.7 中对我来说就像一个魅力!谢谢!!!
【解决方案2】:

Rails 绝对支持开箱即用,检查您的迁移,您是否在 user_id 行中包含了诸如 :null =&gt; false 之类的约束?如果是这样,把它拿出来!

编辑:或如@Rodrigo Dias 所述,将其反转为:null =&gt; true

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

【讨论】:

  • 或者直接切换到 :null => true
  • 我将我的迁移添加到了 OP(没有将其粘贴到此处,因为换行符会失效)。
  • 我使用change_column :products, :user_id, :integer, null: true 进行了迁移,但没有任何效果。
  • 您使用的是哪个版本的 Ruby? null: true 我认为只能在 1.9 之后使用,请尝试 :null =&gt; true 代替
  • @tsm 试试change_column_null :products, :user_id, true
【解决方案3】:

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

【讨论】:

  • belongs_to 要求父对象在创建时默认存在。如果您将创建一个没有父对象的子对象,您将收到["&lt;parent&gt; must exist"] 错误消息,因此您的对象无效。对于解决方案检查@Alexis 回答
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-20
相关资源
最近更新 更多