2012-10-15 12 views
5

Ich habe drei Modelle: Benutzer, Produkt, Angebot und ein Problem mit der Beziehung zwischen diesen Modellen.Produkt Bestellungen zwischen 2 Benutzer

Szenario:

Benutzer 1 Beiträge ein Produkt

Benutzer 2 können Benutzer 1 ein Angebot mit einem Preis zB 10 $

Benutzer senden 1 kann das Angebot

annehmen oder ablehnen

Meine Fragen sind jetzt:

Was ist die richtige Beziehung zwischen Benutzer, Produkt und Angebot?

Wie kann ich mit diesen Aktionen "Akzeptieren oder Ablehnen" umgehen?

Gibt es vielleicht eine bessere Lösung?

User-Modell:

class User < ActiveRecord::Base 
    attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :avatar, :screen_name 
    has_many :products 
    has_many :offers,:through => :products 
end 

Produktmodell:

class Product < ActiveRecord::Base 
    attr_accessible :content, :price, :title, :tag_list, :productimage, :user_id 
    belongs_to :user 
    has_many :offers, :through => :users 
end 

Modell Angebot:

class Offer < ActiveRecord::Base 
    attr_accessible :offer_price, :status, :user_id, :product_id 
    has_many :products 
    has_many :users, through: :products 
end 

Vielen Dank im Voraus :)

EDIT:

Ich bin mit Rails 3.2.8

Antwort

5

Warnung: hier kommt ein kleiner Roman.

Teil 1: die Verbände

Einrichtung Ich würde empfehlen, die Rails guide on associations gründlich, Lesezeichen, um es zu lesen, und lesen Sie es erneut, denn dies ist eine wichtige Sache ist richtig zu verstehen und kann ein bisschen schwierig sein - Es gibt viele Möglichkeiten, wenn Sie über grundlegende Zusammenhänge hinausgehen.

Eine Sache, die Sie über Ihre App bemerken, ist, dass Ihre Benutzer zwei Rollen haben, Käufer und Verkäufer. Sie müssen mit den Namen Ihrer Assoziationen vorsichtig sein - Gibt @user.offers die Angebote zurück, die der Benutzer hat gemacht, oder die Angebote der Benutzer hat erhalten? Vielleicht möchten Sie in der Lage sein, Listen dieser beiden Dinge in das Profil des Benutzers einzutragen.

Die grundlegenden Beziehungen Sie beschreiben, sind recht einfach:

  • Ein Benutzer viele Produkte verkaufen können, so User has_many :products und Product belongs_to :user

  • Ein Nutzer viele Angebote machen, so User has_many :offers und Offer belongs_to :user

  • Ein Produkt kann viele Angebote erhalten, also Product has_many :offers und Offer belongs_to :product

Das ist alles schön und gut ist, und man konnte sicher nur um dies zu tun bekommen - in dem Fall, dass Sie überspringen nach unten können zu Teil 2 :)

jedoch, sobald Sie die hinzuzufügen starten versuchen through Beziehungen werden die Gewässer schlammig werden. Immerhin

  • Offer belongs_to :user (der Käufer), aber es hat auch einen Benutzer durch Produkt (der Verkäufer)

  • User has_many :products (dass sie verkaufen), aber sie haben auch viele Produkte über Angebote (dass sie kaufen - na ja, versuchen zu kaufen).

Aargh, verwirrend!

Dies ist der Punkt, an dem Sie die :class_name -Option benötigen, mit der Sie eine Assoziation anders als die Klasse, auf die sie verweist, und die :source -Option benennen können, mit der Sie Assoziationen im 'from' -Modell anders benennen können als 'through Modell.

So können Sie dann Ihre Assoziationen wie folgt bilden:

# 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 

Obwohl, wenn Sie Ihre user_id Spalten seller_id in der products Tabelle umbenannt und buyer_id in der offers Tabelle, würden Sie nicht brauchen, um diese :foreign_key Optionen .

Teil 2: Annehmen/Abweisen Angebote

Es gibt eine Reihe von Möglichkeiten, dies zu bewältigen. Ich würde ein boolean Feld accepted auf Offer setzen und dann könnte man so etwas wie

# Offer 
def accept 
    self.accepted = true 
    save 
end 

def reject 
    self.accepted = false 
    save 
end 

und Sie können die hervorragenden Angebote finden (wo accepted null ist)

scope :outstanding, where(accepted: nil) 

Um die Annahme/Ablehnungs Logik zu erhalten passiert in der Steuerung, könnten Sie adding new RESTful actions betrachten (die verlinkte Anleitung ist eine weitere lesenswerte Sache!). Sie sollten eine Zeile wie

resources :offers 

in config/routes.rb finden, die die Standardaktionen index bietet, show, edit, etc. Sie können es zu

ändern
resources :offers do 
    member do 
    post :accept 
    post :reject 
    end 
end 

und so etwas wie diese setzen in Ihrem OffersController

def accept 
    offer = current_user.offers_received.find(params[:id]) 
    offer.accept 
end 

# similarly for reject 

Dann können Sie eine POST-Anforderung an offers/3/accept ausgeben und es wil l Das Angebot mit der ID 3 wird angenommen. So etwas wie dies in einer Ansicht sollte es tun:

link_to "Accept this offer", accept_offer_path(@offer), method: :post 

Bitte beachte, dass ich nicht nur Offer.find(params[:id]) schreiben, weil dann ein schlauer Benutzer Angebote auf dem Namen des Verkäufers akzeptieren könnte. Siehe Rails Best Practices.

+0

Vielen Dank für Ihre Antwort. Ich denke, das funktioniert :) Ich werde die anderen Optionen testen. Noch eine Frage: Wie kann ich das zu meinem Angebotscontroller hinzufügen? Sorry für diese noob Fragen, aber ich lerne immer noch. –

+0

Kein Problem, das ist eine gute Frage! Ich habe meine Antwort aktualisiert, um es zu erklären. –

+0

Ich habe Probleme, diese Migration zu visualisieren. Sollte die Offers-Tabelle nur einen Fremdschlüssel für 'user_id' und' product_id' haben? – sabaeus

2

Wie wäre es

class User < ActiveRecord::Base 
    has_many :products # All products posted by this user 
    has_many :offers # All offers created by this user 
end 

class Product < ActiveRecord::Base 
    belongs_to :user # This is the user who posts the product (User 1) 
    has_many :offers 
end 

class Offer < ActiveRecord::Base 
    belongs_to :product 
    belongs_to :user # This is the user who creates the offer (User 2) 

    # Use a 'state' field with values 'nil', 'accepted', 'rejected' 
end 

Für Ihr Szenario:

# User 1 posts a product 
product = user1.products.create 

# User 2 can send User 1 an offer with an price e.g $ 10 
offer = user2.offers.create(:product => product) 

# User 1 can accept or reject the offer 
offer.state = 'rejected' 

Sie diese je nach Bedarf verfeinern könnten - zum Beispiel wenn das gleiche Produkt von verschiedenen Benutzern gepostet werden könnte.

4

Ihre Modelle sind gut genug, außer für die Beziehungen. Die Verwirrung beginnt, wenn Sie versuchen, die eigenen Produkte von den interessierten Produkten (angeboten) und den Produkteigentümer von den interessierten Benutzern (die das Angebot abgegeben haben) zu unterscheiden. Wenn Sie eine bessere Namenskonvention treffen können, können Sie es leicht beheben.

1. Bessere Beziehungen

class User < ActiveRecord::Base 
    attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :avatar, :screen_name 
    has_many :owned_products, :class_name => "Product" 
    has_many :offers 
    has_many :interested_products, :through => :offers 
end 

class Offer < ActiveRecord::Base 
    attr_accessible :offer_price, :status, :user_id, :product_id 
    belongs_to :interested_user, :class_name => "User", :foreign_key => :user_id 
    belongs_to :interested_product, :class_name => "Product", :foreign_key => :product_id 
end 

class Product < ActiveRecord::Base 
    attr_accessible :content, :price, :title, :tag_list, :productimage, :user_id 
    belongs_to :owner, :foreign_key => :user_id, :class_name => "User" 
    has_many :offers 
    has_many :interested_users, :through => :offers 
end 

Mit diesen Beziehungen denke ich, mit allen grundlegenden Informationen zu erhalten, können Sie interessiert sein würde. Zum Beispiel

@product = Product.find(1) 
@product.owner # would give you the user who created the product 
@product.interested_users # would give you users who placed an offer for this product 

@user = User.find(1) 
@user.owned_products # would give you the products created by this user 
@user.interested_products # would give you the products where the user placed an offer 

2. Handhabung akzeptieren und Maßnahmen abzulehnen.

Aus Ihrer Beschreibung sehe ich, dass es zwei mögliche Statusänderungen zu einem Angebot geben kann, "erstellt" -> "akzeptieren" oder "erstellt" -> "ablehnen". Ich empfehle Ihnen, sich state_machine anzusehen.State Machine fügt deinem Modell mit seinen Hilfsmethoden einen schönen Geschmack hinzu, was meiner Meinung nach in deinem Fall sehr nützlich sein wird. Also Ihr Offer Modell wird in etwa so aussehen,

class Offer < ActiveRecord::Base 
    # attr_accessible :title, :body 
    attr_accessible :offer_price, :status, :user_id, :product_id 
    belongs_to :interested_user, :class_name => "User", :foreign_key => :user_id 
    belongs_to :interested_product, :class_name => "Product", :foreign_key => :product_id 

    state_machine :status, :initial => :created do 
    event :accept do 
     transition :created => :accepted 
    end 
    event :reject do 
     transition :created => :reject 
    end 
    end 
end 

#cool helper methods 
@offer = Offer.new 
@offer.accepted? #returns false 
@offer.reject #rejects the offer 
@offer.rejected? #returns true 

Ich hoffe, das gibt Ihnen ein besseres Bild.