web-dev-qa-db-fra.com

Rails facultatif appartient_à

J'écris un Rails frontend pour la gestion des stocks. Je veux que les utilisateurs puissent enregistrer des produits, j'ai donc:

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

et

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

Le problème est que les produits sont créés avant d'être enregistrés par un utilisateur. Autrement dit, il est parfaitement acceptable d'appeler Product.create et il suffit de régler le user_id à nil. Comme vous pouvez l'imaginer, cependant, Rails ne prend pas cela en charge:

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

J'ai pensé à un tas de solutions de contournement kludgey, dont la plus intéressante est d'avoir un sous-classement NullUserUser et de l'utiliser pour créer des produits. Mais cela semble toujours être un hack. Quelle est la manière Rails avec cela?

Merci.


La migration pertinente:

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

et ensuite:

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

Avez-vous une validation qui nécessite que l'utilisateur soit présent? Si oui, supprimez cela.

6
user1454117

Juste une mise à jour pour Rails 5, si vous voulez ce genre de comportement, vous devrez passer cette option:

belongs_to :user, optional: true

Dans Rails 5, chaque fois que nous définissons une association d'appartenance, il est nécessaire que l'enregistrement associé soit présent par défaut.

Mise à jour
Si vous souhaitez toujours utiliser l'ancien comportement par défaut, vous pouvez ajouter la configuration à votre fichier application.rb.

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

notice: il y avait quelques problèmes sur les premières versions de Rails 5 avec cette configuration, mais est actuellement corrigé, testé sur la version candidate 5.2.3 .

194
Alexis

Rails le prend absolument en charge, vérifiez votre migration, avez-vous inclus une contrainte telle que :null => false sur le user_id ligne? Si oui, sortez-le!

Modifier: ou, comme l'indique @Rodrigo Dias, inversez-le en :null => true.

Vérifiez également que vous n'avez aucune validation sur la relation utilisateur dans le modèle de produit.

5
Matt