5

ユーザー、製品、オファーの 3 つのモデルがあり、これらのモデル間の関係に問題があります。

シナリオ:

ユーザー 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 を使用しています

4

3 に答える 3

7

警告: ここに小さな小説があります。

パート 1: 関連付けの設定

関連付けに関する Rails ガイドをよく読み、ブックマークして、もう一度読むことをお勧めします。これは、適切に理解するための重要な事項であり、少しトリッキーになる可能性があるためです。基本的な関連付けを超えると、多くのオプションがあります。

このアプリについて注意すべきことの 1 つは、ユーザーには買い手と売り手の 2 つの役割があることです。関連付けの名前には注意が必要です。ユーザーが行ったオファーまたはユーザーが受け取っ@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名前を関連付けに付けることができるオプションと、「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

ただし、テーブル内およびテーブル内でuser_id列の名前を に変更した場合、これらのオプションは必要ありません。seller_idproductsbuyer_idoffers:foreign_key

パート 2: オファーを受け入れる/拒否する

これに対処する方法はいくつかあります。ブール値フィールドacceptedを配置するOfferと、次のようなものを持つことができます

# Offer
def accept
  self.accepted = true
  save
end

def reject
  self.accepted = false
  save
end

そして、あなたは未解決のオファーを見つけることができます(どこacceptedがnullです)

scope :outstanding, where(accepted: nil)

コントローラーで承認/拒否ロジックを実行するには、新しい RESTful アクションを追加することを検討してください (リンクされたガイドも、よく読む価値があります!)。次のような行が見つかるはずです

resources :offers

config/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と、ID 3 のオファーが受け入れられます。ビューでこのようなことを行う必要があります。

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

Offer.find(params[:id])悪意のあるユーザーが売り手に代わってオファーを受け入れる可能性があるため、私が書いただけではないことに注意してください. Rails のベスト プラクティスを参照してください。

于 2012-10-15T12:15:13.007 に答える
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 つの状態変更が考えられることがわかります。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

これにより、より良いイメージが得られることを願っています。

于 2012-10-15T12:13:48.383 に答える
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'

ニーズに応じてこれを調整できます。たとえば、同じ製品が異なるユーザーによって投稿される可能性がある場合などです。

于 2012-10-15T11:40:04.890 に答える