0

我有一个简单的 has_many belongs_to 关系,我想为 belongs_to 模型的视图包含父对象,我已经取得了一些成功,但我希望它能够更好地工作。

class Submission < ActiveRecord::Base
  belongs_to :user
  belongs_to :contest
end
class Contest < ActiveRecord::Base
  belongs_to :user
  has_many :submissions, :dependent => :destroy
end

在可行的情况下,我通过将竞赛 ID 放在 url 中将其传递给提交:

   <%= link_to 'Submit Contest Entry', new_submission_path(:contest_id => @contest.id), 
                            :class => 'btn btn-primary btn-large mleft10' %>

因此,结合 hidden_​​field:

 <%= f.hidden_field :contest_id %>

以及控制器中的 find_contest 方法(使用 before_filter 调用):

def find_contest
  #the next line is giving the error (line 76)
  @contest = Contest.find(params[:submission][:contest_id])
end

使其适用于提交/新建,但是如何将查找添加到仅适用于不止一个页面的控制器中,就像我想在显示和索引中访问一样。现在,我收到一个错误:

Started GET "/submissions?contest_id=5" for 127.0.0.1 at 2012-12-01 16:01:45 -0800
Processing by SubmissionsController#index as HTML
  Parameters: {"contest_id"=>"5"}
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 2 ORDER BY users.created_at DESC LIMIT 1
Completed 500 Internal Server Error in 37ms

NoMethodError (undefined method `[]' for nil:NilClass):
  app/controllers/submissions_controller.rb:76:in `find_contest'

[编辑]为提交添加显示操作:

before_filter :find_contest, :except => [:index, :show, :edit, :update, :destroy]

def find_contest
  @contest = Contest.find(params[:submission][:contest_id])
end

def show
  contest_id = @submission.contest_id
  @submission = @commentable = Submission.find(params[:id])
  @comments = @commentable.comments.order(:created_at).reverse
  respond_to do |format|
    format.html  # show.html.erb
    format.json  { render :json => @submission }
  end
end
4

2 回答 2

0

您正在访问控制器SubmissionsController的操作索引;我假设在动作索引中您正在调用方法find_contest。该错误是因为在方法find_contest内部您试图获取params[:submission][:contest_id]的值,但这样的参数不存在;你得到的参数是params[:contest_id]

为了通过许多操作管理相同的方法,您可以做的是更改方法并传递参数,如下所示:

def find_contest(contest_id)
  @contest = Contest.find(contest_id)
end

def index
  find_contest(params[:contest_id])
  #some other code...
end

但是,如果您使用的是before_filter之类的东西,您可以检查find_contest方法内部是否存在params[:contest_id].nil? 如果不是 nil 使用它,否则使用params[:submission][:contest_id]

于 2012-12-02T20:20:39.870 回答
0

这是这个问题的答案,但我对 index 和 show 都使用了两行,可能可以重构为一个(编辑说明:Pablo89 建议重构 show,包括在内,但 index 仍然是两行)

然而,这两行在这两种情况下都非常重要,尤其是对于初学者来说,原因如下:

为了将 parent_id (contest_id) 传递到关联视图(显示提交),我使用 params 中的 submit_id 定义了 @submission (@associated)(commentable 用于其他目的,可以忽略)。

@submission = @commentable = Submission.find(params[:id])

参数可以在网站地址中找到,在这种情况下:

http://localhost:3000/submissions/41

41 是submission_id。这很明显。

Rails 使用在浏览器窗口中找到的页面地址来分配实例值。在此之前,我不知道 Rails 在哪里找到参数,因为 Rails 会自动完成很多事情。params 是网页地址。哦!

然后我使用@submission 的比赛ID 键分配了比赛ID,这是belongs_to 关联的一部分,并使用find 到达@contest

contest_id = @submission.contest_id
@contest = Contest.find(contest_id)

正如 Pablo89 指出的那样,由于 rails 的关联能力,有两条线可以简化为一条:

@contest = @submission.contest

在索引中,没有@submission,所以我通过link_to那个页面将contest_id传递给这个页面,在两个地方找到contests/show和submissions/show:

<%= link_to 'Browse All Submissions', submissions_path(:contest_id => @contest.id), :class => 'btn btn-mini pull-right' %>

单击链接将带您进入提交/索引并在此地址中找到结果:

http://localhost:3000/submissions?contest_id=4

(:contest_id => @contest.id) 将 ?contest_id=4 添加到地址中,以便我可以通过“params”从提交控制器访问它

对于像我这样的初学者来说,这是建立对参数的理解的重要方法,因为页面的地址是 Rails 从 @submission 或 @contest 分配其实例变量的地方。

嵌套路由如下所示:

比赛/5/submssions/41

如果您使用的是嵌套路由,那么比赛和提交值就在地址中,就在那里,等待使用!该地址也称为“参数”,(我重复它以了解像我这样头骨很厚的其他学习者),但如果您不使用嵌套路由,则必须以另一种方式传递父 ID,例如添加它到上面例子中的link_to。

从那里访问 ?contest_id=4 我将以下内容放入提交的索引操作中:

contest_id = params[:contest_id]
@contest = Contest.find(contest_id)

这对我来说是一个突破,因为到目前为止,我从来不知道 params 是什么或它是如何工作的,只是它起作用了。

通过理解这个基本概念,大多数有经验的开发人员都非常了解他们不想提及的内容,我对控制器了解得更多。

我在这里转达的所有内容可能正确也可能不正确,但我希望这对其他初学者有所帮助。我现在对自己解决问题的能力更有信心。在此之前,我对 params 所做的大部分工作都是尝试不同的方式,直到它在没有任何基本了解的情况下工作。它现在让我发笑,因为它真的很简单。我认为 params 这个词有点可怕,因为它可以指代任何地方的任何参数。

现在我知道了,这是 Rails 用来分配这些值的网址参数。哇!多么大的突破……

于 2012-12-02T22:51:44.940 回答