你并没有完全按照 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 => "view_auction", :id => @bid.auction_id 和<% form_for :bid, :url => {:controller => "auction", :action => "add_bids"} do |f|%>。使用 RESTful 路由,它们变为 redirect_to @auction 和 `
这里有一些你应该阅读的资源:
-
ActiveRecord::Associations:定义了 has_many、belongs_to、它们的选项以及它们添加的便捷方法。
-
Understanding MVC:更好地理解与 Rails 相关的信息流
-
RESTful resources:了解资源。
-
Form Helpers:对 form_for 的深入描述以及上述代码的工作原理。