文系でもプログラマーになりたい!

文系プログラマー(になりたい人)のメモです。現在、プログラミングスクールで学習中。WEBエンジニアへの転職目指して活動中です!

初心者がLINEのオウム返しBOTを作る(Ruby on Rails)

始めてLINEのオウム返しBOTを作ったので、そのお話。

こんな感じのやつです。

f:id:zoekun:20200603053153j:plain



 

開発環境

Ruby 2.5.1

Ruby on Rails 5.2.4.2
Heroku

 

手順

Line Developersへの登録

 こちらの記事を参考にさせていただきました。

 

2アプリケーションの作成

Botのアプリケーションを作成します。

$ rails new app-name -d postgresql

②gemの導入
gem 'line-bot-api'
gem 'dotenv-rails' 

③コントローラーへの記載
class BotController < ApplicationController
  require 'line/bot'
  protect_from_forgery :except => [:callback]

  def client
    client = Line::Bot::Client.new { |config|
        config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
        config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    }
  end

  def callback
    body = request.body.read
    # LINEプラットフォームからのリクエストであることをボットサーバーでリクエストヘッダーのX-Line-Signatureに含まれる署名を検証します。
    signature = request.env['HTTP_X_LINE_SIGNATURE']

    unless client.validate_signature(bodysignature)
      head :bad_request
    end
    
    events = client.parse_events_from(body)

    # LINEからメッセージが送られるなどイベントが発生した時
    events.each do |event|
      case event
      # イベントがメッセージだった時
      when Line::Bot::Event::Message
        case event.type
        # そのメッセージがテキストだった時、それをそのまま返す。
        when Line::Bot::Event::MessageType::Text
          message = {
            type: 'text',
            text: event.message['text']
          }
        end
      end
      client.reply_message(event['replyToken'], message)
    end
    head :ok
  end
end

④ルートの設定
Rails.application.routes.draw do
  post '/callback' => 'bot#callback'
end

⑤Herokuへのデプロイ
アプリケーションのディレクトリ内
heroku login  
heroku create
gitのmasterにpush後
git push heroku master  

⑥Herokuへの環境変数の設定
ENV["LINE_CHANNEL_SECRET"]
ENV["LINE_CHANNEL_TOKEN"]

このままでは上の2つが空なので、変数を設定します。

heroku config:set LINE_CHANNEL_SECRET=Channel Secretを貼り付け
heroku config:set LINE_CHANNEL_TOKEN=アクセストークンを貼り付け

Channel Secretは
Line Developersの「チャンネル基本設定」
アクセストークンは「Messaging API」から確認することができます。

⑦Webhook URLの設定
同じく、「Messaging API」のページでWebhook URLを設定します。
heroku open
で開いたページのURL/callbackでWebhook URLを登録します。
Webhook URL
heroku openで開いたページのURL/callback

確認

LINEで友達登録して、きちんと動作しているか確認しましょう。
正常に動いていれば、入力したのと同じ文字が返信されるはずです。

最後に

想像より簡単にできて驚きました。
今後、もっと改良していろんな機能を実装したいと思います。

参考にさせていただいたサイト

https://yuilog.xyz/linebot_code

https://qiita.com/y428_b/items/d2b1a376f5900aea30dc

https://qiita.com/takashico/items/edb6050a8e54dd137148

Rubyでバブルソートを書く

学習備忘録、今回はRubyバブルソートを書いてみました。

 

バブルソートって何?

隣あう二つの数字を比較し、並びかえをこなうアルゴリズム

大きな数字は右側にソートされていく。

 

sortメソッドでも同じことができる。

 

サンプルコード

# こちらがバブルソート
def bubble(ary)
  ary.length.times do |i|
    (ary.length-(i+1)).times do |k|
      if ary[k> ary[k+1]
        ary[k],ary[k+1= ary[k+1],ary[k]
      end
    end
  end
end

bubble = [657,123,2,89]
bubble(bubble)
p bubble


# sortメソットの場合
a = [657,123,2,89]
p a.sort

【出力結果】

[2, 89, 123, 657]

[2, 89, 123, 657]

 

どちらも同じ結果を出力することができる。

バブルソートでは、timesメソッドで繰り返し回数を決めた後、

隣あう要素を取り出し、数が大きい方を右側にソートする と言う手順を繰り返して

全体のソートを行う。

参考にさせていただいたサイト

https://qiita.com/RyumaRyama/items/6753bf32d435f74690be

https://programming-beginner-zeroichi.jp/articles/286

Ruby で FizzBuzz問題を解く

 学習の一環でrubyFizzBuzz問題を解いたのでまとめます。

 

FizzBuzz問題って何?

数字を1から順に言い、

3で割り切れる数の時は「Fizz」、

5で割り切れる数も時は「Buzz」、

15で割り切れる数の時は「FizzBuzz」と言うゲーム。

「プログラムを書けるプログラマ」を見分けるためのテストとして良く知られている。

 

Rubyで書いてみよう

回答は一個ではない。様々な方法でFizzBuzz問題のプログラムを書くことが出来る。

条件分岐は15で割り切れる場合から、書くのが重要!

 

①each文で書く。

繰り返しのeach文で書くとこうなる。

(1..100).each do |a|
  if a%15 == 0
    puts "FizzBuzz"
  elsif a%5 == 0
    puts "Buzz" 
  elsif a%3 == 0
    puts "Fizz"
  else
    puts a
  end
end

 

②while文で書く

条件を満たすかぎり繰り返されるWhile文だとこうなる。

a = 1
while a <= 100 
  if a%15 == 0
    puts "fizzbuzz"
  elsif a%5 == 0
    puts "Buzz" 
  elsif a%3 == 0
    puts "Fizz"
  else
    puts a
  end
  a += 1 
end

 

③timesを使って書く

繰り返しの回数を決めるtimesを使うとこう

a = 1
100.times do
  if a%15 == 0
    puts "fizzbuzz"
  elsif a%5 == 0
    puts "Buzz" 
  elsif a%3 == 0
    puts "Fizz"
  else
    puts a
  end
  a += 1 
end

④upto を使って書く

上限を決められるuptoで書くとこうなる。

a = 1
1.upto(100do
  if a%15 == 0
    puts "fizzbuzz"
  elsif a%5 == 0
    puts "Buzz" 
  elsif a%3 == 0
    puts "Fizz"
  else
    puts a
  end
  a += 1 
end

実行結果

正しく表示されていればOK!

1
2
4
Buzz
7
8
Buzz
11
13
14
16
17
19
Buzz
22
23
Buzz
26
28
29
31
32
34
Buzz
37
38
Buzz
41
43
44
46
47
49
Buzz
52
53
Buzz
56
58
59
61
62
64
Buzz
67
68
Buzz
71
73
74
76
77
79
Buzz
82
83
Buzz
86
88
89
91
92
94
Buzz
97
98
Buzz

 

間違いやもっといいコードがあれば、教えていただければ幸いです。

よろしくお願いします。

 

【Ruby on Rails】Pay.jpでクレジットカード登録・削除機能を実装する

某プログラミングスクールで学習中の著者です。

Pay.jpでクレジットカード登録・削除機能を実装したので、

記録として残しておきます。

 

開発環境

Rails 5.2.4.2
ruby 2.5.1 

 

実装する機能

 Pay.jpでクレジットカード登録・削除機能

(登録画面も写真みたいに作ります。)

f:id:zoekun:20200519075431j:plain

 

実装手順

①Pay.jpのサイトでアカウントを作成(こちらをクリック

②gemファイルに gem 'payjp' を記載し、bundle installする

gem 'payjp'

③application.html.hamlに payjp.jsを読み込めるようにする。

%script{src: "https://js.pay.jp/"type: "text/javascript"} を追記する

(これにより、カード情報をトークン化できるようになります)

%html
  %head
    %meta{:content => "text/html; charset=UTF-8""http-equiv" => "Content-Type"}/
    %title fulima
    -# ↓これ
    %script{src: "https://js.pay.jp/"type: "text/javascript"}
    -# 
    = csrf_meta_tags
    = stylesheet_link_tag    'application'media: 'all'
    = javascript_include_tag 'application'

 

④カード情報を保存するテーブルを作成する。

マイグレーションファイルを作成し、以下のように記載。

その後、ターミナル で rails db:migrate を行います。

class CreateCards < ActiveRecord::Migration[5.2]
  def change
    create_table :cards do |t|
      t.integer :user_idforeign_key: truenull: false
      t.string :customer_idnull: false
      t.string :card_idnull: false
      t.timestamps
    end
  end
end

*ここに登録される customer_id、card_id を用いてPay.jpから顧客情報やカード情報を

 取得します。(カード情報そのものをDBに保存する訳ではありません)

⑤コントローラーの作成

今回は credit という名前で作成しました。

pay メソッドがカードの情報を保存する処理に相当します。

class CreditController < ApplicationController
  require "payjp"
  before_action :set_cardonly: [:index:delete:show]
  before_action :get_payjp_infoonly: [:pay:delete:show]

  def new
  end

  def pay #pay.jpとcardデータベースへのデータを保存する処理
    if params['payjp_token'].blank?
      redirect_to action: :new
    else
      customer = Payjp::Customer.create(
      description: 'test'#なくてもOK
      email: current_user.email,#なくてもOK
      card: params['payjp_token'], 
      metadata: {user_id: current_user.id}
      )
      @card = Card.new(user_id: current_user.idcustomer_id: customer.idcard_id: customer.default_card)
      if @card.save
        redirect_to action: :index
      else
        redirect_to action: :new
      end
    end
  end

  def delete 
    if @card.present?
      customer = Payjp::Customer.retrieve(@card.customer_id)
      customer.delete
      @card.delete
    end
      redirect_to action: :index
  end

  def show
    if @card.blank?
      redirect_to action: :index
    else
      customer = Payjp::Customer.retrieve(@card.customer_id)
      @default_card_information = customer.cards.retrieve(@card.card_id)
    end
  end


  def index
    redirect_to action: :show,id:current_user.id if @card.present?
  end

 

  private
  
  def get_payjp_info
    Payjp.api_key = Rails.application.credentials.dig(:payjp:PAYJP_SECRET_KEY)
  end

  def set_card
    @card = Card.where(user_id: current_user.id).first
  end
end

get_payjp_info では、秘密鍵の設定を行っています。

今回は、credentials.yml に秘密鍵を記載したため、このような記述になっています。

 

秘密鍵の確認方法、PAY.jpのAPIで確認することができます。

(今回は、テスト秘密鍵を使いました)

 

⑥登録画面の作成

f:id:zoekun:20200519075431j:plain

写真のような、カード情報の登録画面を作ります。

(コード見辛くてすみません)

.mypage-content
  %section.purchace
    %h2.profile__top クレジットカード情報入力
    .content
      = form_with url: pay_credit_index_pathmethod: :posthtml: { name: "inputForm" } do |f|
        .content__inner
          .resister-credit
            = f.label :カード番号class: "resister-credit__number" 
            %span.resister-credit__need 必須
            = f.text_field :card_numbername: "number"id:"number"type: 'text'placeholder: "半角数字のみ"maxlength: "16"class:"resister-credit__text"
            %ul.resister-credi__errow
            %ul.resister-credi__card
              = image_tag "credit01.JPG"class: "resister-credit__list"
          .resister-credit.margin
            = f.label :有効期限class: "resister-credit__number" 
            %span.resister-credit__need 必須
            %br
            .resister-credit__limit
              = f.select :exp_month, [["01",1],["02",2],["03",3],["04",4],["05",5],["06",6],["07",7],["08",8],["09",9],["10",10],["11",11],["12",12]],{}, class: "resister-credit__limit__mm"name: "exp_month"id: "exp_month"
              %i.fas.fa-chevron-down
              %span 月
            .resister-credit__limit
              = f.select :exp_year, [["19",2019],["20",2020],["21",2021],["22",2022],["23",2023],["24",2024],["25",2025],["26",2026],["27",2027],["28",2028],["29",2029]],{}, class: "resister-credit__limit__mm"name: "exp_year"id:"exp_year"
              %i.fas.fa-chevron-down
              %span 年
          .resister-credit.margin
            = f.label :セキュリティーコードclass: "resister-credit__number" 
            %span.resister-credit__need 必須
            = f.text_field :cvcname: "cvc"id:"cvc"type: 'text',placeholder: "カード背面4桁もしくは3桁の番号"maxlength: "4",class:"resister-credit__text"
          .submitter
            = f.submit "追加する"class: 'profile__top__content__button margin'id: "token_submit"
     - #↓これ忘れないように!
          %input{:id => "card_token":type => "hidden"}



 この時、%input{:id => "card_token":type => "hidden"} の記載を

忘れないようにしましょう

(この後、出てくるjsで作ったトークンを送信するための記載です)

(自分はこれを忘れたせいで、丸1日悩み続けました)

javascriptにデータを送り、トークンを取得する。(jquery使用)

 

document.addEventListener(
  "DOMContentLoaded"e => {
    if (document.getElementById("token_submit"!= null) { 
      Payjp.setPublicKey("pk_test_fa4c0aef52ad35e72960c1b3"); //公開鍵をセット
      let btn = document.getElementById("token_submit"); 
      btn.addEventListener("click"e => { 
        e.preventDefault(); 
        var card = {
          number: document.getElementById("number").value,
          cvc: document.getElementById("cvc").value,
          exp_month: document.getElementById("exp_month").value,
          exp_year: document.getElementById("exp_year").value
        }; 
        Payjp.createToken(card, (statusresponse=> {
          if (status === 200) { 
            $("#number").removeAttr("name"); //データがDBに保存されないよう削除する
            $("#cvc").removeAttr("name"); //データがDBに保存されないよう削除する
            $("#exp_month").removeAttr("name"); //データがDBに保存されないよう削除する
            $("#exp_year").removeAttr("name"); //データがDBに保存されないよう削除する
            $("#card_token").append(
              $('<input type="hidden" name="payjp_token">').val(response.id)
            ); //トークンを送信出来る状態にする。
            document.inputForm.submit();
            alert("登録が完了しました"); 
          } else {
            alert("カード情報が正しくありません。"); 
          }
        });
      });
    }
  },
  false
);

 

⑧確認画面の作成

f:id:zoekun:20200519091613j:plain

こんな感じの、登録情報の確認画面を作ります。

カードの登録がない時は、コントローラーでカードの登録ボタンが表示されるようにしています。

 

.mypage-content
  %section.purchace
    %h2.profile__top 支払い情報
    .resister
      %h3.resister__title 登録クレジットカード情報
      .resister__form
        = form_with url: delete_credit_index_pathmethod: :postlocal: true do |f|
          %br
          .resister__form__number
            = "**** **** **** " + @default_card_information.last4
          %br
          .resister__form__number
            - exp_month = @default_card_information.exp_month.to_s
          .resister__form__number
            - exp_year = @default_card_information.exp_year.to_s.slice(2,3)
          .resister__form__number
            = exp_month + " / " + exp_year
          = f.submit "削除する"class: 'resister__form__delete'

 

⑨ルートの作成

resources :creditonly: [:new:index:showdo
    collection do
      post :pay
      post :delete
    end
  end

 

⑩テストカードで登録確認

最後はテストカード(Pay.jpで用意されているダミーのカード)で登録確認。

 

登録ができれば、成功です!

お疲れ様でした。

 

参考にさせていただいたサイト

https://qiita.com/takachan_coding/items/f7e70794b9ca03b559dd

https://pay.jp/

css 背景をスクロールしても下まで伸ばしたかった話

どーもZOEです。

CSSで詰まった部分をメモがわりに書いときます!

 

今回、詰まったのは height: 100%; について

ちゃんと100%って書いてあるのに画面の一番下まで適応してくれない。

.side-bar{
  height100%;
}

 

<解決策>

application.css

 

htmlbody{
  height100%;
}

 

これで解決できました。

ちゃんと全体で100%を定義してあげないといけないみたいですね