2012-10-15 9 views
5

Mam trzy modele: użytkownik, produkt, oferta i problem z relacją między tymi modelami.Zamówienia produktów między 2 użytkownikami

scenariusz:

User 1 postów wprowadzający produkt

User 2 można wysłać Użytkownik 1 ofertę z ceną np 10 $

Użytkownik 1 może zaakceptować lub odrzucić ofertę

Moje pytania są następujące:

Jaka jest właściwa relacja między Użytkownikiem, Produktem i Ofertą?

W jaki sposób mogę obsłużyć te działania "zaakceptuj lub odrzuć"?

Czy jest lepsze rozwiązanie?

modelu użytkownika:

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 

Model urządzenia: model

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

Oferta:

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

góry dzięki :)

EDIT:

Używam Rails 3.2.8

Odpowiedz

5

Ostrzeżenie: oto mała powieść.

Część 1: Konfiguracja skojarzeń

polecam czytanie Rails guide on associations dokładnie, zakładka niego i czytać go ponownie, ponieważ jest to kluczowy rzeczą, aby właściwie zrozumieć, a może być nieco kłopotliwe - istnieje wiele opcji, gdy wyjdziesz poza podstawowe skojarzenia.

Jedna rzecz, jaką należy zauważyć, to fakt, że Twoi użytkownicy mają dwie role, kupujących i sprzedających. Musisz być ostrożny z nazwami swoich powiązań - Czy @user.offers zwraca oferty, które użytkownik ma wykonane, lub oferty użytkownik ma otrzymał? Możesz chcieć umieścić listę obu tych rzeczy w profilu użytkownika.

Podstawowe relacje jesteś opisujące są dość proste:

  • Użytkownik może sprzedać wiele produktów, więc User has_many :products i Product belongs_to :user

  • Użytkownik może dokonać wiele ofert, więc User has_many :offers i Offer belongs_to :user

  • Produkt może otrzymać wiele ofert, więc Product has_many :offers i Offer belongs_to :product

To wszystko dobrze i dobre, i można na pewno dostać się tylko to robi - w takim przypadku można pominąć w dół do części 2 :)

jednak jak najszybciej rozpocząć próby dodania through relacje wody będą zamulone. Po tym wszystkim,

  • Offer belongs_to :user (nabywca), ale ma też użytkownika przez produkt (sprzedający)

  • User has_many :products (są one sprzedaży), ale mają również wiele produktów z oferty (że kupują - cóż, próbują kupić).

Aargh, mylące!

Jest to moment, w którym potrzebna jest opcja :class_name, która pozwala nazwać powiązanie inaczej niż klasa, do której się odnosi, oraz opcję :source, która pozwala inaczej nazywać asocjacje w modelu 'od' ' Model.

Więc można następnie tworzyć swoje skojarzenia tak:

# 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 

Chociaż jeśli przemianowany swoje user_id kolumn do seller_id w tabeli products i buyer_idoffers w tabeli, nie będzie potrzebował tych :foreign_key opcje .

Część 2: przyjmowanie/odrzucanie ofert

Istnieje wiele sposobów, aby uporać się z tym. Chciałbym umieścić logiczną pole accepted na Offer a następnie można mieć coś podobnego

# Offer 
def accept 
    self.accepted = true 
    save 
end 

def reject 
    self.accepted = false 
    save 
end 

i można znaleźć znakomite oferty (gdzie accepted jest null)

scope :outstanding, where(accepted: nil) 

Aby uzyskać zaakceptować/odrzucić logikę dzieje się w kontrolerze, możesz wziąć pod uwagę adding new RESTful actions (dołączony przewodnik jest kolejnym wartym przeczytania!). należy znaleźć linię, jak

resources :offers 

w config/routes.rb, który stanowi standardowe działania index, show, edit, itd. Można go zmienić na

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

i umieścić coś takiego w swojej OffersController

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

# similarly for reject 

Następnie można wysłać żądanie POST do offers/3/accept i Wil l proponuję przyjęcie oferty o identyfikatorze 3. Coś takiego w widoku powinien to zrobić:

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

pamiętać, że nie tylko pisać Offer.find(params[:id]) bo wtedy przebiegły użytkownik może akceptować ofert w imieniu sprzedawcy. Zobacz Rails Best Practices.

+0

Dziękuję za odpowiedź. Myślę, że to działa :) Będę testować inne opcje. Jeszcze jedno pytanie: Jak mogę dodać to do kontrolera moich ofert? Przepraszam za te pytania, ale wciąż się uczę. –

+0

Nie ma problemu, to dobre pytanie! Zaktualizowałem swoją odpowiedź, aby to wyjaśnić. –

+0

Mam problem z wizualizacją tej migracji. Czy tabela Oferty powinna mieć klucz obcy dla "id_użytkownika" i "identyfikator_produktu"? – sabaeus

2

Jak o

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 

Dla scenariusz:

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

Można filtra w zależności od potrzeb - na przykład jeśli ten sam produkt mógł zostać wysłany przez różnych użytkowników.

4

Twoje modele są wystarczająco dobre, z wyjątkiem relacji. Zamieszanie zaczyna się, gdy próbujesz odróżnić posiadane produkty od zainteresowanych produktów (oferowanych) i właściciela produktu w stosunku do zainteresowanych użytkowników (użytkowników, którzy złożyli ofertę). Jeśli możesz wymyślić lepszą konwencję nazewnictwa, możesz łatwo to naprawić.

1. Lepsze stosunki

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 

Z tych relacji Myślę, że można dostać wszystkie podstawowe informacje byłbyś zainteresowany. Na przykład,

@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. Sprzęt przyjęć i odrzuceń działania.

Z Twojego opisu wynika, że ​​mogą wystąpić 2 zmiany stanu oferty, "utworzony" -> "zaakceptuj" lub "utworzono" -> "odrzuć". Proponuję, abyś spojrzał na state_machine.Maszyna stanowa doda miłego smaku do Twojego modelu dzięki swoim pomocniczym metodom, które moim zdaniem będą bardzo przydatne w twoim przypadku. Tak więc model Offer będzie wyglądać tak,

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 

Mam nadzieję, że to daje lepszy obraz.

Powiązane problemy