【问题标题】:Passing params in rails... Breakthrough in understanding params在rails中传递params……理解params的突破
【发布时间】:2012-12-03 11:58:02
【问题描述】:

我有一个简单的 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

【问题讨论】:

  • 您好,您可以显示第 76 行中的代码以及所有相应的方法吗?
  • 你有一个Parameters: {"contest_id"=&gt;"5"},尝试将Contest.find(params[:submission][:contest_id])替换为Contest.find(params[:contest_id])
  • @KienThanh 我收到一个错误:在该方法上找不到没有 ID 的竞赛。通常如何将父对象的实例传递给后代控制器。我知道你必须通过位于提交模型中的密钥 contest_id 来查找它,但我不知道它是什么样的。
  • @pablo89 我编辑了这个问题,在第三个编码部分添加了注释以指出第 76 行。

标签: ruby-on-rails-3 params


【解决方案1】:

您正在访问控制器 SubmissionsController 的操作 index;我假设在动作 index 内部,您正在调用方法 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]

【讨论】:

  • 收到此错误:'Started GET "/submissions/41" 由 SubmissionsController#show 处理为 HTML 参数:{"id"=>"41"} 用户负载 (0.3ms) SELECT "users" .* FROM "users" WHERE "users"."id" = 2 ORDER BY users.created_at DESC LIMIT 1 Submission Load (0.2ms) SELECT "submissions".* FROM "submissions" WHERE "submissions"."id" = $1 ORDER BY submits.created_at DESC LIMIT 1 [["id", "41"]] Completed 500 Internal Server Error in 88ms ArgumentError (error number of arguments (0 for 1)): app/controllers/ submits_controller.rb:79:in find_contest2'
  • 如果我把它放在#show contest_id = @submission.contest_id 中,我会收到 /submissions/41 的回复:&lt;%= link_to @contest, @contest %&gt;
  • 我刚刚看了你的代码,我迷路了,因为contest_id = @submission.contest_id,但直到后来还没有初始化@submission。另外,find_contest2 的方法和我建议的方法一样吗? (而且我没有看到您使用对象@contest,也没有看到任何与find_contest2 相关的before_filter)。最后,您在contest_id = @submission.contest_id 中得到的回应是什么(就像您在 3 cmets 前所说的那样)?
  • 好的,我得到了它的工作,但如果你可以在答案中重新考虑它,我可以接受,因为你帮助我得出了一个答案,我知道可以是改进:contest_id = @submission.contest_id \n @contest = Contest.find(contest_id)
  • 如果submissioncontest 相关联,你可以执行@contest = @submission.contest 之类的操作
【解决方案2】:

Here is an answer to this question,但我对 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 添加到地址,以便我可以通过“参数”从提交控制器访问它

对于像我这样的初学者来说,这是建立对参数的理解的重要方法,因为页面的地址是 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 使用 Web 地址参数来分配这些值。哇!多么大的突破……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多