我有三种模式:用户,产品,优惠以及这些模型之间关系的问题。
情境:
用户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
答案 0 :(得分:6)
警告:这是一本小小说。
第1部分:设置关联
我建议彻底阅读Rails guide on associations,给它添加书签,然后重新阅读,因为这是正确理解的关键所在,而且可能有点棘手 - 一旦超越,有很多选择基本协会。
关于您的应用需要注意的一点是,您的用户有两个角色,买家和卖家。您需要注意关联的名称 - @user.offers
是否会返回用户制作的商品,或用户收到的商品 >?您可能希望能够将这两种内容的列表放在用户的配置文件中。
您所描述的基本关系非常简单:
用户可以销售多种产品,因此User has_many :products
和Product belongs_to :user
用户可以提出多项优惠,因此User has_many :offers
和Offer belongs_to :user
产品可能会收到很多优惠Product has_many :offers
和Offer 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中,它提供标准操作edit
,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
并在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'
您可以根据自己的需要进行优化 - 例如如果不同的用户可以发布相同的产品。