Attention : voici un petit roman.
Partie 1 : mise en place des associations
Je vous recommande de lire le Guide Rails sur les associations Lisez-le attentivement, mettez-le dans vos favoris et relisez-le encore, car il est essentiel de bien le comprendre et cela peut s'avérer un peu délicat - il existe de nombreuses options dès que l'on dépasse les associations de base.
Une chose à noter à propos de votre application est que vos utilisateurs ont deux rôles, les acheteurs et les vendeurs. Vous allez devoir faire attention aux noms de vos associations - Est-ce que @user.offers
retourner les offres que l'utilisateur a sur ou les offres que l'utilisateur a recibido ? Vous pourriez vouloir être en mesure de mettre des listes de ces deux choses dans le profil de l'utilisateur.
Les relations de base que vous décrivez sont assez simples :
-
Un utilisateur peut vendre plusieurs produits, donc User has_many :products
y Product belongs_to :user
-
Un utilisateur peut faire plusieurs offres, donc User has_many :offers
y Offer belongs_to :user
-
Un produit peut recevoir de nombreuses offres de sorte que Product has_many :offers
y Offer belongs_to :product
Tout cela est très bien, et vous pourriez certainement vous en sortir en ne faisant que cela - dans ce cas, vous pouvez passer directement à la partie 2 :)
Cependant, dès que l'on commence à essayer d'ajouter la through
relations les eaux vont devenir boueuses. Après tout,
-
Offer belongs_to :user
(l'acheteur), mais il a aussi un utilisateur par le biais du produit (le vendeur)
-
User has_many :products
(qu'ils vendent), mais ils ont également de nombreux produits à travers des offres (qu'ils achètent - enfin, qu'ils essaient d'acheter).
Aargh, déroutant !
C'est le moment où vous avez besoin de la :class_name
qui vous permet de nommer une association différemment de la classe à laquelle elle se réfère, et l'option :source
qui vous permet de nommer les associations sur le modèle "from" différemment du modèle "through".
Vous pourriez donc former vos associations comme ceci :
# User
has_many :products_selling, class_name: 'Product'
has_many :offers_received, class_name: 'Offer',
through: :products_selling, source: :offers
has_many :offers_made, class_name: 'Offer'
has_many :products_buying, class_name: 'Product',
through: :offers_made, source: :product
# Product
belongs_to :seller, class_name: 'User', foreign_key: :user_id
has_many :offers
has_many :buyers, class_name: 'User', through: :offers
# Offer
belongs_to :product
belongs_to :buyer, class_name: 'User', foreign_key: :user_id
has_one :seller, class_name: 'User', through: :product
Bien que si vous avez renommé votre user_id
colonnes pour seller_id
dans le products
table, et buyer_id
dans le offers
table, vous n'auriez pas besoin de ces :foreign_key
options.
Partie 2 : accepter/rejeter les offres
Il y a plusieurs façons de s'attaquer à ce problème. Je mettrais un champ booléen accepted
en Offer
et alors vous pourriez avoir quelque chose comme
# Offer
def accept
self.accepted = true
save
end
def reject
self.accepted = false
save
end
et vous pourriez trouver les offres exceptionnelles (où accepted
est nulle)
scope :outstanding, where(accepted: nil)
Pour que la logique d'acceptation/de rejet se produise dans le contrôleur, vous pouvez envisager de ajout de nouvelles actions RESTful (le guide en lien est un autre guide qui mérite d'être lu attentivement). Vous devriez trouver une ligne comme
resources :offers
dans config/routes.rb, qui fournit les actions standards index
, show
, edit
etc. Vous pouvez le changer en
resources :offers do
member do
post :accept
post :reject
end
end
et mettez quelque chose comme ceci dans votre OffersController
def accept
offer = current_user.offers_received.find(params[:id])
offer.accept
end
# similarly for reject
Ensuite, vous pouvez envoyer une requête POST à offers/3/accept
et il fera en sorte que l'offre avec l'id 3 soit acceptée. Quelque chose comme ça dans une vue devrait faire l'affaire :
link_to "Accept this offer", accept_offer_path(@offer), method: :post
Notez que je n'ai pas seulement écrit Offer.find(params[:id])
car un utilisateur astucieux pourrait alors accepter des offres au nom du vendeur. Voir Meilleures pratiques Rails .