k12da
@k12da (K Yoshida)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

外部APIに入力フォームの値のリクエストを渡して、DBに保存したい

解決したいこと

入力フォームからの情報をHeartrailsGeoAPI(外部API)へリクエストで送り、最終的に住所をDBに保存したいです。
下記の記事を参考にコードを書き、Postmanで値を検証したのですが、NomethodErrorなどが出ます。
https://qiita.com/4ma9147/items/2d377dedf9237b54ba37

※今回マスターテーブルを作成しており、Officeモデルの外部キーに設定しているMunicipalityカラム(市区町村)と、外部APIのCityカラムの値が一致したら、DBに保存したいという実装を考えています。

発生している問題・エラー

"status": 500,
    "error": "Internal Server Error",
    "exception": "#<NoMethodError: undefined method `[]' for nil:NilClass\n\n      
    params = URI.encode_www_form(params[:postal])\n

スクリーンショット 2022-11-26 17.04.39.png

該当するソースコード

office.rb
require 'json'
require 'net/https'
require 'uri'

class Office < ApplicationRecord

  belongs_to :municipality

  before_validation :searchByPostal
  validates :name, presence: true
  validates :postal, presence: true
  validates :prefecture, presence: true
  validates :city, presence:true
  validates :town, presence: true

  def searchByPostal
      params = URI.encode_www_form(params[:postal])
      uri = URI.parse("https://geoapi.heartrails.com/api/json?method=searchByPostal&postal=#{params[:postal]}")
      response = Net::HTTP.get_response(uri)

      if result = JSON.parse(response.body)
        postal = result["results"][0]["postal"]
        prefecture = result["results"][0]["prefecture"]
        city = result["results"][0]["city"]
        town = result["results"][0]["town"]
      end
  end
end

例)

routes.rb
Rails.application.routes.draw do
  namespace 'api' do
    namespace 'v1' do
      namespace 'clients' do

          namespace :admin do 
            post 'offices', to: 'offices#create'
            resources :offices, defaults: { format: :json } do
              collection do
                 post 'searchByPostal'
              end
            end
          end
       end
    end
  end
end

offices_controller.rb
module Api
    module V1
        module Clients
            class Admin::OfficesController < ApplicationController
                def create
                    @office = Office.create(office_params)
                    municipality_id = Municipality.find_by(name: params[:city])
                    @office.municipality = municipality_id
                    if @office.save!
                    render json: { status: 'SUCCESS', data: @office }
                    else
                        render json: { status: 'ERROR', data: @office.errors }
                    end
                end

               private

                def office_params
                    params.permit(:name, :address, :name_rep, :title, :feature_detail, :type, :established_date, :rooms, :requirements, :public_facilities, :business_entity, :official_site, :tell, :fax)
                end
            end
        end
    end
end

db/migrate/20221016151105_create_offices.rb
class CreateOffices < ActiveRecord::Migration[7.0]
  def change
    create_table :offices do |t|
      t.string :name
      t.references :municipality, foreign_key: true

      t.timestamps
    end
  end
end

自分で試したこと

以下の内容でもoffice.rbを書いてみましたが、うまくいきません。

office.rb
require 'json'
require 'net/https'
require 'uri'

class Office < ApplicationRecord

  belongs_to :municipality

  before_validation :searchByPostal
  validates :name, presence: true
  validates :postal, presence: true
  validates :prefecture, presence: true
  validates :city, presence:true
  validates :town, presence: true

  def searchByPostal
     if params[:postal] == "acitivated"
       @offices = Office.activated
     else
       @offices = Office.inactivated
     end

      params = URI.encode_www_form(params[:postal])
      uri = URI.parse("https://geoapi.heartrails.com/api/json?method=searchByPostal&postal=#{params[:postal]}")
       https = Net::HTTP.new(url.host, url.port)
       https.use_ssl =true
       http.verify_mode = OpenSSL::SSL::VERIFY_NONE
       req = Net::HTTP.get_response(uri.path)
       res = https.request(req)

      if result = JSON.parse(response.body)
        postal = result["results"][0]["postal"]
        prefecture = result["results"][0]["prefecture"]
        city = result["results"][0]["city"]
        town = result["results"][0]["town"]
      end
    # end
  end

end

0

1Answer

modelでparamsは使えないですね
searchByPostal は controllerの処理にしてはいかがですか?

1Like

Comments

  1. @k12da

    Questioner

    以下のsearchByPotalを上記のoffices_controllerに記述してみました。
    こちらのサイトを参考にしました。
    https://jumtech.hatenablog.jp/entry/2016/08/20/140720

    外部APIの値が取得できているかどうかは、postリクエストして確認すればよろしいでしょうか?

        def searchByPostal
    params = URI.encode_www_form{postal: params[:postal]}
    uri = URI.parse("https://geoapi.heartrails.com/api/json?method=searchByPostal&postal=#{params}")
    @query = uri.query
    response = Net::HTTP.start(uri.host, uri.port) do |http|
    http.open_timeout = 5
    http.read_timeout = 10
    http.get(uri.request_uri)
    end
    begin
    case response
    when Net::HTTPSuccess
    @result = JSON.parse(response.body)
    @postal = @result["results"][0]["postal"]
    @prefecture = @result["results"][0]["prefecture"]
    @city = @result["results"][0]["city"]
    @town = @result["results"][0]["town"]
    when Net::HTTPRedirection
    @message = "Redirection: code=#{response.code} message=#{response.message}"
    else
    @message = "HTTP ERROR: code=#{response.code} message=#{response.message}"
    end

    rescue IOError => e
    @message = "e.message"
    rescue TimeoutError => e
    @message = "e.message"
    rescue JSON::ParserError => e
    @message = "e.message"
    rescue => e
    @message = "e.message"
    end
    end
  2. 動作確認は今までもしてたんですよね?同じで良いんじゃないでしょうか

Your answer might help someone💌