2个用户之间的产品订单

时间:2012-10-15 10:22:00

标签: ruby-on-rails ruby relationship belongs-to

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

情境:

用户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

3 个答案:

答案 0 :(得分:6)

警告:这是一本小小说。

第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(他们正在销售),但他们也有许多产品通过优惠(他们正在购买 - 好吧,试图购买)。

Aargh,令人困惑!

当您需要: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 选项,它允许您命名关联的关联。 '模型与'通过'模型不同。

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

user_id

虽然如果您将seller_id列中的products列重命名为buyer_id,并将offers表中的:foreign_key重命名为accepted,则不需要Offer选项。

第2部分:接受/拒绝优惠

有很多方法可以解决这个问题。我会在# Offer def accept self.accepted = true save end def reject self.accepted = false save end 上放置一个布尔字段accepted,然后你可能会有类似

的内容
scope :outstanding, where(accepted: nil)

你可以找到优秀的优惠(resources :offers 为空)

index

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

这样的行
show

在config / routes.rb中,它提供标准操作editresources :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

并在offers/3/accept

中添加类似内容
link_to "Accept this offer", accept_offer_path(@offer), method: :post 

然后,您可以向Offer.find(params[:id])发出POST请求,这将导致接受ID为3的要约。视图中的这样的东西应该这样做:

{{1}}

请注意,我不只是写{{1}},因为那时狡猾的用户可以代表卖家接受优惠。请参阅Rails Best Practices

答案 1 :(得分:4)

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

<强> 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次可能的状态更改,“已创建” - &gt; “接受”或“创建” - &gt; “拒绝”。我建议你看看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

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

答案 2 :(得分: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'

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