XXX:字符串的动作控制器异常未定义方法“合并”

时间:2019-01-08 14:33:02

标签: ruby-on-rails ruby

我正在做类似Reddit的简单网站。我正在尝试向报告帖子添加按钮。我使用report创建了button_to模型,我尝试将数据发布到report controller来创建它,但是我收到了NoMethodError in ReportsController#create undefined method merge' for "post_id":String

model / report.rb

class Report < ApplicationRecord
  belongs_to :reporting_user, class_name: 'Author'
  has_one :post
end

report_controller.rb

class ReportsController < ApplicationController
  def create
    report = Report.new(report_params)

    flash[:notice] = if report.save
                       'Raported'
                     else
                       report.errors.full_messages.join('. ')
                     end
  end

  def report_params
    params.require(:post).merge(reporting_user: current_author.id)
  end

end

和视图中的按钮

= button_to "Report", reports_path, method: :post, params: {post: post}

是什么原因导致了该问题?

编辑:

参数

=> <ActionController::Parameters {"authenticity_token"=>"sX0DQfM0rp97q8i16LGZfXPoSJNx15Hk4mmP35uFVh52bzVa30ei/Bxk/Bm40gnFmd2NvFEqj+Wze8ted66kig==", "post"=>"1", "controller"=>"reports", "action"=>"create"} permitted: false>

3 个答案:

答案 0 :(得分:2)

首先,您要使用belongs_to而不是has_one

class Report < ApplicationRecord
  belongs_to :reporting_user, class_name: 'Author'
  belongs_to :post
end

这样可以将post_id外键列正确地放在reports上。使用has_one会将fk列放在posts上,将不起作用。

通常最好的解决方案是制作报告a nested resource

# /config/routes.rb
resources :posts do
  resources :reports, only: [:create]
end

# app/controller/reports_controller.rb
class ReportsController
  before_action :set_post

  # POST /posts/:post_id/reports
  def create
    @report = @post.reports.new(reporting_user: current_author)
    if @report.save
      flash[:notice] = 'Reported'
    else
      flash[:notice] = report.errors.full_messages.join('. ')
    end
    redirect_to @post
  end

  private

  def set_post 
    @post = Post.find(params[:post_id])
  end
end

这使您可以将按钮简化为:

= button_to "Report", post_reports_path(post), method: :post

由于post_id是路径的一部分,因此我们不需要发送任何其他参数。

如果您希望将来让用户通过表单传递其他信息,则通过传递一个块来创建/更新带有参数和会话数据的资源的更好方法是:

@report = @post.reports.new(report_params) do |r|
  r.reporting_user = current_user
end

答案 1 :(得分:0)

ActionController::Parameters#require返回参数中所需键的值。通常这是一个从表单传回的对象。在this example中,require将返回{name: "Francesco", age: 22, role: "admin"}并进行合并。

您的视图正在发回Rails格式化为{post: 'string'}的参数。我们将需要查看您的视图代码来确定到底需要更改什么。

更新:从发布的新代码中,我们可以看到发送回的参数是"post"=>"1"。通常我们会期望post: {id: 1, ...}

更新:视图中的按钮将需要将params键更新为类似 params: {post: {id: post.id}} 的内容编辑:我同意params: {report: { post_id: post}}是更好的格式。

答案 2 :(得分:0)

问题似乎出在report_params中。当您调用params.require(:post)时,它将从params中获取:post->结果为字符串。您正在此字符串上调用merge

我建议更改视图:

= button_to "Report", reports_path, method: :post, params: { report: { post_id: post} }

然后在控制器中:

def report_params
  params.require(:report).permit(:post_id).merge(reporting_user_id: current_author.id)
end

请注意,我还根据约定更改了命名:model_id用于表示模型,模型或模型本身的ID。