Rails optional belongs_to

Ruby on-RailsRubyActiverecord

Ruby on-Rails Problem Overview


I'm writing a Rails frontend for inventory management. I want users to be able to register products, so I have:

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

and

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

The problem is that products are created prior to being registered by a user. That is, it's perfectly acceptable to call Product.create and just have it set the user_id to nil. As you can imagine, though, Rails doesn't support this out of the box:

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

I've thought about a bunch of kludgey workarounds, the most appealing of which is to have a NullUser subclassing User and use that to create products. But that still seems like a hack. What's the Rails Way with this?

Thanks.


The relevant migration:

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

and later:

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

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

Just an update for rails 5, if you want this kind of behavior you will need to pass this option:

belongs_to :user, optional: true

In Rails 5, whenever we define a belongs_to association, it is required to have the associated record present by default.

Update
If you still want to use the old behavior by default you can add the configuration to your application.rb file.

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

notice: there were some issues on early releases of Rails 5 with this configuration, but is currently fixed, tested on the release candidate 5.2.3.

Solution 2 - Ruby on-Rails

Rails absolutely supports this out of the box, check your migrate, have you included a constraint such as :null => false on the user_id line? If so, take it out!

Edit: Or as @Rodrigo Dias states, reverse it to :null => true.

Also, check that you don't have any validations on the user relation in the Product model.

Solution 3 - Ruby on-Rails

Do you have a validation that requires user be present? If so, remove that.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontsmView Question on Stackoverflow
Solution 1 - Ruby on-RailsAlexisView Answer on Stackoverflow
Solution 2 - Ruby on-RailsMattView Answer on Stackoverflow
Solution 3 - Ruby on-Railsuser1454117View Answer on Stackoverflow