简体   繁体   中英

NoMethodError: undefined method `get' for RSpec

First of all, this is my first experience with ruby. At this moment, I'm creating tests for the a Controller called Exporter in my application. The method of the Controller I want to test is this:

def export_as_json(equipments)
    equipments_json = []
    equipments.each {|equipment|
        equipment_json = {
            :id => equipment.id,
            :title => equipment.title,
            :description => equipment.description,
            :category => equipment.category_id
        }
        equipments_json << equipment_json
    }

    respond_to do |format|
      format.json { render :json =>equipments_json }
    end
end

So, when I try to create a request for this method using this:

RSpec.describe ExporterController, type: :controller do
  get '/equipments/all', headers: { 'CONTENT_TYPE' => 'application/json' }, format: :json
  expect(response.response).to eq(200)
end

inside the exporter_controller_test.rb file I'm receiving this error:

NoMethodError: undefined method `get' for RSpec::ExampleGroups::ExporterController:Class

This is one of the problems pretty much every one runs into at least once ;)

Step 1: Read the error message very carefully

NoMethodError: undefined method 'get' for RSpec::ExampleGroups::ExporterController:Class

Step 2: Remember the wording NoMethodError: undefined method get for RSpec::ExampleGroups::XXX:Class

Step 3: Solve it by making it an actual example

RSpec.describe ExporterController, "#index", type: :controller do
  it "should respond with status: 200" do
    get '/equipments/all', headers: { 'CONTENT_TYPE' => 'application/json' }, format: :json
    expect(response.response).to eq(200)
  end
end

You were simply missing the it block.

I know this is not an answer to your question. But, since you mentioned that you're new to ruby, I thought I would point out that your code could be simplified and prettified a bit.

First, you don't need to do equipments_json = [] and then equipments.each . That's what map is for:

def export_as_json(equipments)
  equipments_json = equipments.map{|equipment| {
      :id => equipment.id,
      :title => equipment.title,
      :description => equipment.description,
      :category => equipment.category_id
    }
  }

  respond_to do |format|
    format.json { render :json =>equipments_json }
  end
end

Now, that hash you're putting into equipments_json is just a subset of equipment 's attributes. So, use slice there to get the attributes you want:

def export_as_json(equipments)
  equipments_json = equipments.map{|equipment| equipment.attributes.slice('id','title','description','category_id')}

  respond_to do |format|
    format.json { render :json =>equipments_json }
  end
end

That map line is still a little long, so, maybe put it into a do block (like you had with each ):

def export_as_json(equipments)
  equipments_json = equipments.map do |equipment| 
    equipment.attributes.slice('id','title','description','category_id')
  end

  respond_to do |format|
    format.json { render :json =>equipments_json }
  end
end

And personally, I like using symbols instead of strings as my keys, so use with_indifferent_access so that you can use symbols:

def export_as_json(equipments)
  equipments_json = equipments.map do |equipment| 
    equipment.attributes.with_indifferent_access.slice(:id, :title, :description, :category_id)
  end

  respond_to do |format|
    format.json { render :json =>equipments_json }
  end
end

That line got a little to long again, so I think I would go ahead and wrap it:

def export_as_json(equipments)
  equipments_json = equipments.map do |equipment| 
    equipment.
      attributes.
      with_indifferent_access.
      slice(:id, :title, :description, :category_id)
  end

  respond_to do |format|
    format.json { render :json =>equipments_json }
  end
end

Now, there are some different ways to get those attributes you want (eg, modifying to_json ). But, this will get the job done.

Hope that helps and good luck!

PS: I just noticed in your original hash, you're doing:

:category => equipment.category_id

if that's not a typo and you really want category instead of category_id , then you could do something like:

def export_as_json(equipments)
  equipments_json = equipments.map do |equipment| 
    equipment.
      attributes.
      with_indifferent_access.
      slice(:id, :title, :description).
      merge!(category: equipment.category_id)
  end

  respond_to do |format|
    format.json { render :json =>equipments_json }
  end
end

Also, the convention for hashes is to do title: equipment.title . :title => equipment.title absolutely works, but is not the current convention. This is a style guide for ruby, in case it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM