【问题标题】:Associating multiple ids on creation of Item在创建项目时关联多个 id
【发布时间】:2009-10-15 15:41:22
【问题描述】:

G'day 伙计们,

我目前正在构建一个测试“拍卖”网站来学习 Rails。我已经设置了我的拍卖和用户模型,并且只有经过身份验证的用户才能编辑或删除与其关联的拍卖。

我遇到的困难是将投标项目与拍卖相关联。

我的模型如下:


class Auction < ActiveRecord::Base
  belongs_to :creator, :class_name => "User"
  has_many :bids
  validates_presence_of :title
  validates_presence_of :description
  validates_presence_of :curprice
  validates_presence_of :finish_time
  attr_reader :bids

  def initialize
    @bids = []
  end

  def add_bid(bid)
    @bids << bid
  end
end

class Bid < ActiveRecord::Base
  belongs_to :auction, :class_name => "Auction", :foreign_key => "auction_id"
  belongs_to :bidder, :class_name => "User", :foreign_key => "bidder_id"

  validates_presence_of :amount
  validates_numericality_of :amount
  @retracted = false
end

class User < ActiveRecord::Base
  has_many :auctions, :foreign_key => "owner_id"
  has_many :bids, :foreign_key => "owner_id" 
#auth stuff here
end

我正在尝试将出价记录添加到拍卖中,但auction_id 根本不会添加到记录中。

我在拍卖视图中创建一个带有值的出价,将@auction 作为本地变量。

<% form_for :bid, :url => {:controller => "auction", :action => "add_bids"} do |f|%>

<p>Bid Amount <%= f.text_field :amount %></p>
<%= submit_tag "Add Bid", :auction_id => @auction %> 
<% end %> 

这是连接到以下代码:

def add_bids
    @bid = current_user.bids.create(params[:bid])
   if @bid.save
     flash[:notice] = "New Bid Added"
     redirect_to :action => "view_auction", :id => @bid.auction_id
    end   
 end

我遇到的问题是auction_id 没有放入bid 元素中。我尝试将其设置为 HTML 格式,但我认为我遗漏了一些非常简单的内容。

我的数据模型,回顾一下是

用户同时进行出价和拍卖

拍卖有一个用户并且有很多出价

出价有用户并进行拍卖

在过去的 4 个小时里,我一直在努力解决这个问题,我开始对这一切感到非常沮丧。

任何帮助将不胜感激!

【问题讨论】:

  • 请使用代码块使您的帖子更清晰。最简单的方法是突出显示并单击文本区域上方的 101010 按钮。

标签: ruby-on-rails


【解决方案1】:

你并没有完全按照 Rails 的方式做事,这让你有点困惑。 在 Rails 中成功的编码就是约定优于配置。意思是,除非您另有说明,否则 Rails 会猜测您的意思。如果它猜错了,它通常会尝试几件事。但总的来说,坚持使用确定性名称就可以了。

你的代码有这么多错误,所以我要把它清理干净,把cmets各种方式让你知道哪里出了问题。

app/models/auction.rb

class Auction < ActiveRecord::Base 
  belongs_to :creator, :class_name => "User" 
  has_many :bids 

  # Given the nature of your relationships, you're going to want to add this      
  # to quickly find out who bid on an object.
  has_many :bidders, :through => :bids

  validates_presence_of :title 
  validates_presence_of :description 
  validates_presence_of :curprice 
  validates_presence_of :finish_time attr_reader :bids

  #These two methods are unnecessary.

  # Also don't override initialize in ActiveRecord. Instead use after_initialize

  #def initialize   Supplied by rails when you do has_many :bids 
  #  @bids = []     @bids will be populated by what is picked up from 
  #end              the database based on the has_many relationship

  #def add_bid(bid) Supplied by rails when you do has_many :bids  
  #  @bids << bid   auction.bids << is a public method after has_many :bids   
  #end 
end

app/models/bid.rb

class Bid < ActiveRecord::Base 
  # :class_name and :foreign_key are ony necessary when rails cannot guess from a
  # association name. :class_name default is the association singularized and
  # capitalized. :foreign_key default is association_id

  belongs_to :auction #, :class_name => "Auction", :foreign_key => "auction_id" 

  # here we need :class_name because Rails is looking for a Bidder class.
  # also there's an inconsistency. Later user refers to has_many bids with 
  # a foreign_key of owner_id, which one is it? bidder_id or owner_id?
  # if it's owner_id? you will need the :foreign_key option.

  belongs_to :bidder, :class_name => "User" #, :foreign_key => "bidder_id"

  validates_presence_of :amount 
  validates_numericality_of :amount 

  # This will never get called in a useful way.
  # It really should be done in the migration, setting default
  # value for bids.retracted to false

  # @retracted = false 
end

app/models/user.rb

class User < ActiveRecord::Base 
  # This makes sense, because an auction can have many bidders, who are also users.

  has_many :auctions, :foreign_key => "owner_id" 

  # This doesn't. A bid belongs to a user, there's no need to change the name. 
  # See above note re: owner_id vs. bidder_id

  has_many :bids, :foreign_key => "owner_id" 

  # You could also use this to quickly get a list of auctions a user has bid on

  has_many :bid_on_auctions, :through => :bids, :source => :auction
  ... auth stuff ...
end

到目前为止一切都很好,对吧?

视图还不错,但缺少投标金额的表单部分。此代码假定您将出价值存储在金额列中。我还随意命名为auctions/bid

app/views/auctions/bid.html.erb

<% form_for :bid, @auction.bids.new do |f|%>
  <%= f.label_for :amount %>
  <%= f.text_field :amount%>

<!-- Don't need to supply @auction.id, because form_for does it for you. -->
<%= submit_tag "Add Bid" %> 

params hash 由表单生成:即传递给控制器​​:

params = 
  { 
    :bid => 
    { 
      :auction_id => @auction.id
      :amount => value of text_field
     }
  }

在您编写时由 from 生成的参数哈希(注意:我猜测名称是因为它们被排除在发布的代码之外):

params = 
  { 
    :id => @auction_id ,
    :bid => { :amount => value of text_field }
  }

但是,您的控制器代码是所有问题的根源,这几乎是完全错误的。我猜这是在拍卖控制器中,这似乎是错误的,因为您正在尝试创建出价。让我们看看为什么:

app/controllers/auctions_controller.rb

...
def add_bids 
  # not bad, but... @bid will only fill in the owner_id/bidder_id. and bid amount.

  @bid = current_user.bids.create(params[:bid])

  # create calls save, so this next line is redundant. It still works though. 
  # because nothing's happening between them to alter the outcome of save.

  if @bid.save 
    flash[:notice] = "New Bid Added" 

    # you should be using restful routes, this almost works, but is ugly and deprecated.
    # it doesn't work becasue @bid.auction_id is never set. In fact you never use 
    # the auction_id any where, which was in your params_hash as params[:id]
    redirect_to :action => "view_auction", :id => @bid.auction_id
   end
end
...

这是您的控制器的工作方式。首先,这应该在bids_controller,而不是auctions_controller

app/controllers/bids_controller.rb

...
def create
  @bid = Bid.new(params[:bid]) # absorb values from form via params
  @bid.bidder = current_user # link bid to current_user.
  @auction = bid.auction based on.

  # @auction is set, set because we added it to the @bid object the form was based on.

  if @bid.save 
    flash[:notice] = "New Bid Added" 
    redirect_to @auction #assumes there is a show method in auctions_controller
  else 
    render "auctions/show" # or what ever you called the above view
  end
end
...

您还需要确保您的 routes.rb 中包含以下内容(除了可能已经存在的内容。这几行将为您设置 RESTful 路由。

config/routes.rb

ActionController::Routing::Routes.draw do |map|
  ...
  map.resources :auctions
  map.resources :bids
  ...
end

无论如何,你离得不远了。看来您的起步不错,并且可能会从阅读有关 Rails 的书中受益。如果你不了解底层框架,只是盲目地遵循教程对你没有多大好处。 90% 的教程都是针对旧版本的 rails 和过时的,这无济于事。

您的很多代码都是旧的做事方式。特别是redirect_to :action =&gt; "view_auction", :id =&gt; @bid.auction_id&lt;% form_for :bid, :url =&gt; {:controller =&gt; "auction", :action =&gt; "add_bids"} do |f|%&gt;。使用 RESTful 路由,它们变为 redirect_to @auction 和 `

这里有一些你应该阅读的资源:

  1. ActiveRecord::Associations:定义了 has_many、belongs_to、它们的选项以及它们添加的便捷方法。
  2. Understanding MVC:更好地理解与 Rails 相关的信息流
  3. RESTful resources:了解资源。
  4. Form Helpers:对 form_for 的深入描述以及上述代码的工作原理。

【讨论】:

  • 非常感谢,这太棒了。你是一个绝对的救星!
  • 如果你打算继续使用 StackOverflow,你应该养成投票和接受正确答案的习惯。声望达到 15 人后您才能投票,但您发布的每个问题都可以接受一个答案。
猜你喜欢
  • 1970-01-01
  • 2013-09-08
  • 1970-01-01
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多