2个用户之间的产品订单

我有三个模型:用户,产品,优惠以及这些模型之间关系的问题。

场景:

用户1发布产品

用户2可以向用户1发送价格为10美元的报价

用户1可以接受或拒绝该优惠

我现在的问题是:

用户,产品和优惠之间的正确关系是什么?

我该如何处理这些“接受或拒绝”的行为?

可能有更好的解决方案吗?

用户模型:

class User  :products end 

产品型号:

 class Product  :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

警告:这是一本小小说。

第1部分:建立关联

我建议仔细阅读关于关联的Rails指南 ,给它添加书签,然后重新阅读,因为这是正确理解的关键,并且可能有点棘手 – 一旦超出基本关联,有很多选项。

关于您的应用需要注意的一点是,您的用户有两个角色,买家和卖家。 您将需要小心您的关联名称 – @user.offers是否返回用户提供的优惠或用户收到的优惠 ? 您可能希望能够将这两样的列表放在用户的配置文件中。

您描述的基本关系非常简单:

  • 用户可以销售许多产品,因此User has_many :productsProduct belongs_to :user

  • 用户可以提供很多优惠,因此User has_many :offers Offer belongs_to :userOffer belongs_to :user

  • 产品可能会收到许多优惠,因此Product has_many :offers Offer belongs_to :productOffer belongs_to :product

这一切都很好,你可以做到这一点 – 在这种情况下你可以跳到第2部分:)

然而,一旦你开始尝试添加through关系,水就会变得混乱。 毕竟,

  • Offer belongs_to :user (买方),但它也有用户通过产品(卖方)

  • User has_many :products (他们正在销售),但他们也有很多产品通过优惠(他们正在购买 – 好吧,试图购买)。

Aargh,令人困惑!

当你需要:class_name选项,它允许你为它所引用的类命名一个关联时,以及:source选项,它允许你将’from’模型上的关联命名为’through’模型。

所以你可能会像这样形成你的联想:

 # 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 

虽然如果您在productsseller_id user_id列重命名为seller_id ,并在productsseller_id重命名为seller_id ,则不需要:foreign_key选项。

第2部分:接受/拒绝要约

有很多方法可以解决这个问题。 我会在Offer accepted一个布尔字段,然后你可能会有类似的东西

 # Offer def accept self.accepted = true save end def reject self.accepted = false save end 

你可以找到优秀的报价(如果accepted为空)

 scope :outstanding, where(accepted: nil) 

要在控制器中发生接受/拒绝逻辑,您可以考虑添加新的RESTful操作 (链接指南是值得仔细阅读的另一个指南!)。 你应该找到像这样的一行

 resources :offers 

在config / routes.rb中,它提供标准操作indexshowedit等。您可以将其更改为

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

并在您的OffersController这样的OffersController

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

然后,您可以向offer offers/3/accept发出POST请求,这将导致offers/3/accept id为3的商品。 视图中的这样的东西应该这样做:

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

请注意,我不只是写Offer.find(params[:id])因为那时狡猾的用户可以代表卖家接受报价。 请参阅Rails最佳实践 。

除了关系之外,你的模型足够好。 当您尝试区分自有产品与感兴趣的产品(提供)和产品所有者与感兴趣的用户(提供优惠的用户)时,就会产生混淆。 如果您能提出更好的命名约定,则可以轻松修复它。

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.处理接受和拒绝操作。

根据您的描述,我看到可能有两种可能的状态更改,“创建” – >“接受”或“创建” – >“拒绝”。 我建议你看看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 

我希望这会给你一个更好的画面。

怎么样

 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 eg $ 10 offer = user2.offers.create(:product => product) # User 1 can accept or reject the offer offer.state = 'rejected' 

您可以根据需要对其进行优化 - 例如,如果不同用户可以发布相同的产品。