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 NullUser
User
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
Avez-vous une validation qui nécessite que l'utilisateur soit présent? Si oui, supprimez cela.
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 .
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.