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 :products
和Product belongs_to :user
-
用户可以提供很多优惠,因此
User has_many :offers
Offer belongs_to :user
和Offer belongs_to :user
-
产品可能会收到许多优惠,因此
Product has_many :offers
Offer belongs_to :product
和Offer 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
虽然如果您在products
表seller_id
user_id
列重命名为seller_id
,并在products
表seller_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中,它提供标准操作index
, show
, edit
等。您可以将其更改为
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'
您可以根据需要对其进行优化 - 例如,如果不同用户可以发布相同的产品。