为什么将此哈希视为字符串?

时间:2018-08-14 11:17:56

标签: ruby-on-rails ruby

问题

当我调用Hash#merge函数时,我很难理解为什么我的哈希被视为字符串。调用以下代码时,我收到一个NoMethodError method 'merge' for #<String:0x000...

引发错误的代码行如下:topic.publish({subject: 'LAB_COMPLETE', message: lab_attribs.merge(full_name: current_user.full_name)}.to_json)。出于某种原因,Ruby将lab_attribs变量视为String而不是Hash。根据以下来源,我可能看不到这是怎么回事。

来源

lab_attribs = {
    name: create_params['lab_name'],
    completed: DateTime.now,
    duration: create_params['duration'],
    final_grade: create_params['final_grade'],
    cpe: create_params['cpe'],
    user_id: create_params['user_id']
}

lab = Lab.new(lab_attribs)

if lab.save
  logger.debug("lab_attribs class: #{lab_attribs.class}, lab_attribs value: #{lab_attribs}" )
  sns = Aws::SNS::Resource.new
  topic = sns.topic(Rails.application.secrets.lab_results_topic)
  topic.publish({subject: 'LAB_COMPLETE', message: lab_attribs.merge(full_name: current_user.full_name)}.to_json)

  render json: { lab_name: lab.name }
else
  render json: { status: 422, errors: lab.errors }
end

相关信息

logger.debug输出以下内容:

lab_attribs class: Hash, lab_attribs value: {:name=>"Updating Firewall Rules", :completed=>Tue, 14 Aug 2018 11:36:01 +0000, :duration=>"1 minute", :final_grade=>"0", :cpe=>"0", :user_id=>"<snipped>"}
  • Ruby版本:2.3.1
  • 发布版本:5.1

日志

I, [2018-08-14T11:36:00.943514 #1930]  INFO -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb] Started POST "/api/v1/labs" for 172.68.65.103 at 2018-08-14 11:36:00 +0000
I, [2018-08-14T11:36:00.946228 #1930]  INFO -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb] Processing by Api::V1::LabsController#create as */*
I, [2018-08-14T11:36:00.946311 #1930]  INFO -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb]   Parameters: {"lab"=>{"lab_name"=>"[FILTERED]", "task1"=>"Saved a local copy of the firewall rules", "score1"=>"0", "weight1"=>"50", "task2"=>"Blocked port 3600", "score2"=>"0", "weight2"=>"50", "final_grade"=>"0", "cpe"=>"0", "duration"=>"1 minute", "user_id"=>"<snipped>"}}
...<snipped DB calls>... 
D, [2018-08-14T11:36:01.408369 #1930] DEBUG -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb] lab_attribs class: Hash, lab_attribs value: {:name=>"Updating Firewall Rules", :completed=>Tue, 14 Aug 2018 11:36:01 +0000, :duration=>"1 minute", :final_grade=>"0", :cpe=>"0", :user_id=>"<snipped>"}
I, [2018-08-14T11:36:01.414112 #1930]  INFO -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb] Completed 500 Internal Server Error in 468ms (ActiveRecord: 26.7ms)
F, [2018-08-14T11:36:01.414612 #1930] FATAL -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb]   
F, [2018-08-14T11:36:01.414689 #1930] FATAL -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb] NoMethodError (undefined method `merge' for #<String:0x0055e4df9d9558>):
F, [2018-08-14T11:36:01.414720 #1930] FATAL -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb]   
F, [2018-08-14T11:36:01.414758 #1930] FATAL -- : [d9f4566a-5b25-4e07-ace3-06f301ecf0cb] app/controllers/api/v1/labs_controller.rb:30:in `create'

2 个答案:

答案 0 :(得分:6)

哈希没有被视为字符串;您误读了该错误。

我不确定您的回溯是否被某些东西意外地截断了,或者您只是编辑了重要部分,但是错误不在您认为的位置。

您正在呼叫merge的事实与您的问题无关,这是因为the publish method you are calling在其参数上调用merge ...您将以{{1} }构建的字符串,而不是预期的哈希值。

您需要删除通话中的to_json

答案 1 :(得分:1)

在哈希上调用to_json会将其转换为字符串。

irb(main):001:0> { foo: 'bar' }.to_json.class
=> String

签名为Aws::SNS::Topic#publish(options = {}) ⇒ Types::PublishResponse

因此,您应该将其称为:

topic.publish(
  subject: 'LAB_COMPLETE', 
  message: lab_attribs.merge(full_name: current_user.full_name).to_json
)

您可以使用Active Job和一些基本的哈希操作来清理整个凌乱的示例:

# app/jobs/publish_job.rb
class PublishJob < ApplicationJob
  queue_as :default

  def perform(**options)
    sns = Aws::SNS::Resource.new
    topic = sns.topic(Rails.application.secrets.lab_results_topic)
    topic.publish(options)
  end
end

# ...
def create
  lab = Lab.new(lab_attributes)
  if lab.save
    PublishJob.perform_now(
     subject: 'LAB_COMPLETE', 
     message: lab_attributes.merge(full_name: current_user.full_name).to_json
    )
    render json: { lab_name: lab.name }
  else
    render json: { status: 422, errors: lab.errors }
  end
end

private 

def lab_attributes
  create_params.slice(:duration, :final_grade, :cpe, :user_id).merge(
    completed: DateTime.now,
    name: create_params[:lab_name]
  )
end