2012-10-15 24 views
5

我有三種模式:用戶,產品,供應和這些模型之間的關係問題。2個用戶之間的產品訂單

場景:

用戶1個職位產品

用戶2可以給用戶1的報價與價格如$ 10

用戶1可以接受或拒絕該要約

我的問題是:

用戶,產品和優惠之間的正確關係是什麼?

我該如何處理這些「接受或拒絕」行爲?

有沒有更好的解決方案?

用戶模式:

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 

產品型號:

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

發售型號:

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

感謝提前:)

編輯:

我用Rails 3.2.8

回答

5

警告:這裏有一本小說。

第1部分:建立協會

我建議你閱讀Rails guide on associations徹底,添加書籤,看了一遍,因爲這是正確理解的關鍵的東西,可以是一個有點棘手 - 一旦超越了基本聯想,就有很多選擇。

有一件事要注意你的應用程序是你的用戶有兩個角色,買家和賣家。你需要小心你的關聯的名稱 - @user.offers是否返回用戶擁有的優惠製造的,或者用戶擁有的優惠收到?您可能希望能夠在用戶的配置文件中放置這兩個列表。

您所描述的基本關係是相當簡單:

  • 用戶可以賣很多產品,所以User has_many :productsProduct belongs_to :user

  • 用戶可以做出許多的優惠,所以User has_many :offersOffer belongs_to :user

  • 產品可能會收到很多優惠Product has_many :offersOffer belongs_to :product

這一切都很好,你可以通過只是在做這個肯定會獲得 - 在這種情況下,你可以跳過了第2部分:)

然而,一旦你開始嘗試添加through水域將變得泥濘的關係。總之,

  • Offer belongs_to :user(買方),但它也有通過產品用戶(賣方)後

  • User has_many :products通過提供(即他們所銷售),但他們也有很多產品(他們正在購買 - 好吧,試圖購買)。

啊,混亂!

這是一點,當你需要的:class_name選項,它可以讓你以不同名稱的結合,它指的是類,而:source選項,它可以讓你的名字在「從」模型關聯不同的「通過'模型。

所以,你可能再形成的協會是這樣的:

# 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 

但如果你在offers表重命名你的user_idseller_idproducts表,buyer_id,你就不需要那些:foreign_key選項。

2部分:接受/拒絕報價

有多種方式來解決這一點。我會把一個布爾字段acceptedOffer,然後你可以有像

# Offer 
def accept 
    self.accepted = true 
    save 
end 

def reject 
    self.accepted = false 
    save 
end 

,你可以找到優秀的報價(其中accepted爲null)

scope :outstanding, where(accepted: nil) 

要得到接受/拒絕邏輯發生在控制器中,你可能會考慮adding new RESTful actions(鏈接指南是另一個值得仔細閱讀!)。你應該找到像

resources :offers 
在配置

/routes.rb中的線,它提供了標準操作indexshowedit等,您可以將其更改爲

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

,並把這樣的事情在OffersController

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

# similarly for reject 

然後你就可以發出一個POST請求offers/3/accept並願買電子健康l導致ID 3的報價被接受。像這樣的事情在一個視圖中應該這樣做:

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

請注意,我不只是寫Offer.find(params[:id])因爲這樣一個狡猾的用戶可以接受賣方的代表提供。見Rails Best Practices

+0

謝謝你的回答。我認爲這有效:)我會測試其他選項。還有一個問題:我如何將這個添加到我的報價控制器?對不起,這些noob問題,但我還在學習。 –

+0

沒問題,這是一個很好的問題!我已經更新了我的答案來解釋它。 –

+0

我在查看此遷移時遇到問題。 Offers表應該有'user_id'和'product_id'的外鍵嗎? – sabaeus

2

如何

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 

對於您的情況:

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

你可以細化這取決於你的需求 - 例如如果相同的產品可以由不同的用戶發佈。

4

除了關係之外,你的模型已經足夠好了。當您試圖區分擁有產品vs感興趣的產品(提供)和產品所有者vs感興趣的用戶(提供該產品的用戶)時,混亂就開始了。如果你能想出一個更好的命名約定,你可以很容易地修復它。

1.改善關係

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 

有了這些關係,我認爲你可以得到所有你會感興趣的基本信息。 例如,

@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.處理接受和拒絕動作。

從您的描述中,我發現可能會有2個可能的狀態更改爲「創建」 - >「接受」或「創建」 - >「拒絕」。我建議你看看state_machine。狀態機將通過其輔助方法爲您的模型添加美味,我認爲這對您的情況非常有用。所以,你的Offer模式會是這個樣子,

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 

我希望這給你一個更好的畫面。