20191026のRubyに関する記事は12件です。

Rubyの文法 memo初心者【rails学習①】v-2

目的と内容

学習内容の整理と後日の参照用。他者へのポートフォリオ用。

今回はRuby文法のまとめ。

基本

コメント

1行の場合
#シャープ以下はコメントになる

下記でも、コメントアウトにはなるが、こちらはソースコードにドキュメントを埋め込むための記述
=begin
beginとend間のドキュメントが埋め込まれる
=end

メソッド

puts
画面に出力するためのメソッド、文末で改行される

print
画面に出力するためのメソッド、文末で改行されない

Random#rand()
引数を渡さない(もしくは引数が0)の場合、0以上1未満の浮動小数点数をランダムに生成するメソッド
rand(1..10)など、括弧内で生成する値の範囲を決められる

分岐

if.rb
if 条件式
    処理
elsif 条件式
    処理
else
    処理
end

繰り返し

for.rb
for カウンタ変数 in 繰り返し範囲(配列でもOK
    処理
end
while.rb
while 条件式
    処理
    カウンタ変数を更新
end

型の変更

  • to_i 整数へ
  • to_f 浮動小数点数へ
  • to_s 文字列へ
  • to_a 配列へ
  • to_h ハッシュへ

標準入力

gets.rb
example = gets

他、chomp(末尾の改行を取り除くメソッド)と併用することが多そう。

配列 

array.rb
exarray = [, , , ]  #代入

exarray.push()    #末尾に値を追加

exarray.detete(0)   #0番目を削除

各要素をループで取り出したい場合

each.rb
exarray.each do |変数名|
    処理
end

exarray.each do |変数名、変数名2| #インデックス番号も一緒に取得したい場合
    処理
end

メソッド

Array#map()
配列の各要素に同じ処理を加えたい場合

String#split()
指定の記号で分割し、配列として戻す

Array#sort
要素が<=>で比較可能であれば並び替える

Array#reverse
配列を現在と逆の順序に並び替える

ハッシュ

hash.rb
exhash = { => ,  => ,  => }  

キーにシンボルを使った場合、下記のようにも記述できる。

hash.rb
exhash = {: => ,: => ,: => }  
#または
exhash = {:, :, :}  

各要素をループで取り出したい場合

hash.rb
exhash.each_values do |変数名|
    処理
end

exhash.each do |変数名, 変数名2| #キーも一緒に取り出したい場合
    処理
end

メソッド

method.rb
def exmethod()
    処理
end

メソッド内で定義された変数は独立している。
外から同じ名前の変数を使いたい場合は、\$exampleのように\$マークを先頭につけたグローバル変数をつかう必要があるが、これはあまり使われない。

クラス

基本

class.rb
class Exclass 
    @@exclass             #クラス変数(よくわかっていない
    attr_accessor :exam   
    def initialize(exam)  #初期化メソッド(必ず実行される
        @exam = exam      #インスタンス変数(よくわかっていない
    end
end

クラス名の最初の一文字は必ず大文字にする。
attr_accessor : ◯◯はインスタンス変数を外から変更できるようにするためのコード。(よくわかっていない)

継承

親クラスのメソッド、変数を子クラスでもつかえる。

オーバーライド

親クラスが持つメソッドを、子クラスで再定義して上書きできる。

private

頭にprivateを付け加えられたメソッドはクラス内からしか呼び出せない。

superメソッド

親クラスの持つメソッドを呼び出す。

その他

ライブラリの読み込み

require 'ライブラリ名'

モジュール

modu.rb
module モジュール名
    def メソッド名()
    end

    module_function :メソッド名
end

モジュールはオブジェクトを作らず、メソッドをそのまま実行することができる。
その場合、『module_function :メソッド名』という記述が必要。
下記、Mix-inを使う場合、『module_function :メソッド名』の記述はつけてはいけない。(よくわかっていない部分

Mix-in

mixin.rb
class クラス名
    include モジュール名
end

例外処理

reigai.rb
begin
    エラーが発生する可能性のある場所
rescue
    エラーが発生した場合
else
    エラーが発生しない場合
ensure
    エラーの有無に関わらず行う処理
end

その他

・コマンド
ファイル名やフォルダ名にスペースが入ってる場合、コマンドでは””を含めて記述
ex) cd "new project"

コマンドラインから現在いる場所をFinderで開きたい場合(Mac)
open .

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyの文法 memo初心者【rails学習①】

目的と内容

学習内容の整理と後日の参照用。他者へのポートフォリオ用。

今回はRuby文法のまとめ。

基本

コメント

1行の場合
#シャープ以下はコメントになる

2行以上の場合
=begin
beginとend間がコメントになる
=end

メソッド

puts
画面に出力するためのメソッド、文末で改行される

print
画面に出力するためのメソッド、文末で改行されない

rand()
0〜1までの数をランダムに生成するメソッド
rand(1..10)など、括弧ないで生成する値の範囲を決められる

分岐

if.rb
if 条件式
    処理
elsif 条件式
    処理
else
    処理
end

繰り返し

for.rb
for カウンタ変数 in 繰り返し範囲(配列でもOK
    処理
end
while.rb
while 条件式
    処理
    カウンタ変数を更新
end

型の変更

  • to_i 整数へ
  • to_f 浮動小数点数へ
  • to_s 文字列へ
  • to_h ハッシュへ

標準入力

gets.rb
example = gets

他、chomp(末尾の改行を取り除くメソッド)と併用することが多そう。

配列 

array.rb
exarray = [, , , ]  #代入

exarray.push() = 値 #末尾に値を追加

exarray.detete(0)  #0番目を削除

各要素をループで取り出したい場合

each.rb
exarray.each do |変数名|
    処理
end

exarray.each do |変数名、変数名2| #インデックス番号も一緒に取得したい場合
    処理
end

メソッド

map()
配列の各要素に同じ処理を加えたい場合

split()
指定の記号で分割し、配列として戻す

sort
配列を文字コード順に並び替える

reverse
配列を文字コードと逆の順序に並び替える

ハッシュ

hash.rb
exhash = { => ,  => ,  => }  #書き方1
exhash = {: => ,: => ,: => }  #書き方2
exhash = {:, :, :}  #書き方3

各要素をループで取り出したい場合

hash.rb
exhash.each_values do |変数名|
    処理
end

exhash.each do |変数名, 変数名2| #キーも一緒に取り出したい場合
    処理
end

メソッド

method.rb
def exmethod()
    処理
end

メソッド内で定義された変数は独立している。
外から同じ名前の変数を使いたい場合は、\$exampleのように\$マークを先頭につけたグローバル変数をつかう必要があるが、これはあまり使われない。

クラス

基本

class.rb
class Exclass 
    @@exclass             #クラス変数(よくわかっていない
    attr_accessor :exam   
    def initialize(exam)  #初期化メソッド(必ず実行される
        @exam = exam      #インスタンス変数(よくわかっていない
    end
end

クラス名の最初の一文字は必ず大文字にする。
attr_accessor : ◯◯はインスタンス変数を外から変更できるようにするためのコード。(よくわかっていない)

継承

親クラスのメソッド、変数を子クラスでもつかえる。

オーバーライド

親クラスが持つメソッドを、子クラスで再定義して上書きできる。

private

頭にprivateを付け加えられたメソッドはクラス内からしか呼び出せない。

superメソッド

親クラスの持つメソッドを呼び出す。

その他

ライブラリの読み込み

require 'ライブラリ名'

モジュール

modu.rb
module モジュール名
    def メソッド名()
    end

    module_function :メソッド名
end

モジュールはオブジェクトを作らず、メソッドをそのまま実行することができる。
その場合、『module_function :メソッド名』という記述が必要。
下記、Mix-inを使う場合、『module_function :メソッド名』の記述はつけてはいけない。(よくわかっていない部分

Mix-in

mixin.rb
class クラス名
    include モジュール名
end

例外処理

reigai.rb
begin
    エラーが発生する可能性のある場所
rescue
    エラーが発生した場合
else
    エラーが発生しない場合
ensure
    エラーの有無に関わらず行う処理
end

その他

・コマンド
ファイル名やフォルダ名にスペースが入ってる場合、コマンドでは””を含めて記述
ex) cd "new project"

コマンドラインから現在いる場所をFinderで開きたい場合(Mac)
open .

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsアプリに投稿されたYouTubeURLを自動的に埋め込み表示させる方法~無理やり編~

1概要

ユーザーがYouTubeにアップロードされた動画のURLを投稿し、それを自動で埋め込み動画としてそのサイトに表示させたい。これやりたい人地味に多いのでは?
実装しようとして意外と記事がなかったので僕がやったやり方を共有。
今回はrailsアプリに投稿されたYouTubeURLがたとえ埋め込みURLでなくても自動でサイトに埋め込み表示させる方法を紹介します。

環境
ruby 2.5.6
Rails 6.0.0

こんな感じのものができる予定

Qiita-gif.gif

1.1. YouTubeURLの種類

YouTubeURLは僕がパッと見た感じ3種類のURLが存在します

PCでのYouTube閲覧時のURL 一番スタンダード?

https://www.youtube.com/watch?v=DOEk-0MeQbI
qiita-1.jpg

共有用URL (スマホで視聴中の動画を友達に共有するときはこれ)

https://youtu.be/DOEk-0MeQbI
qiita-2.jpg

埋め込みURL (これをHTMLに貼り付ければそのページで埋め込み動画になる)

https://www.youtube.com/embed/DOEk-0MeQbI
qiita-3.jpg

1.2. どう実装するか

この3つのURLには共通して末尾に11桁の数字があります。これはGoogleがYouTubeに投稿された全ての動画に割り振っている通し番号でvideo_idと呼ばれます。
つまり上の2種類のURLが投稿されたら末尾の11桁を取り出し、HTMLに設置した以下の埋め込みURLの末尾にその数字を反映させれば埋め込み動画になるはずです。

埋め込みURLの末尾11桁に投稿されたurlの末尾11桁を代入→ https://www.youtube.com/embed/<11桁のvideo_id>

2 実装

2.1 事前準備

それではまずここで使うYouTube動画を投稿するだけのサンプルアプリを作っていきます。

cd 
cd desktop 
rails new YouTubeApps

投稿周りの機能をscaffoldを利用して一瞬で作りましょう。

cd YouTubeApps
rails generate scaffold post body:text youtube_url:string
rails db:migrate

これで投稿周りの機能ができたと思います。それではここからpostsテーブルのyoutube_urlカラムにどんなYouTubeURLが投稿されても埋め込みURLに変えていく記述を書いていきます。

2.2 本題

それではここからyoutubeURLから末尾のvideo_idのみを取り出し埋め込みURLにする実装をしていくのですが、Postsコントローラーのcreateアクションへrubyのコードを記述して行きます。
以下のように、scaffoldによって作成されたコントローラーのcreateアクションにコードを追記してください。

posts_controller.rb
  def create
    @post = Post.new(post_params)
     #追記した部分ここから
    url = params[:post][:youtube_url]
    url = url.last(11)
    @post.youtube_url = url
    #ここまで

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

ここで追記した以下の部分について解説をします。

url = params[:post][:youtube_url]
url = url.last(11)
@post.youtube_url = url

paramsとは

まず一行目のparamsを含む一文について

url = params[:post][:youtube_url]

paramsとはrailsに用意されたgetやpostで送られてきた値を格納するためのメソッドです。
paramsのわかりやすい解説記事
ここでは投稿する際にformによってcreateアクションにpostの内容が

[:body][:youtube_url]

として送られています。

posts_controller
url = params[:post][:youtube_url]

よって、上記のコードにより変数urlに対してparamsに格納している中身であるformによって送られてきた[:youtube_url]の値を格納します。
現在の変数urlの中身は送られてきたurl全文が格納されている状態です。

現在の変数urlの中身

https://www.youtube.com/watch?v=DOEk-0MeQbI

lastメソッドについて

ここから二文目のコードで語尾の11桁のvideo_idを取り出します。

url = url.last(11)

rubyの配列にはlastというメソッドがあります。これを呼ぶことで配列に対してその最後の要素を取得することができます。また、(n)の中に引数として0以上の値を渡すことで、最後のn個の要素を取得することができます。

a=[0,1,2,3]
a.last(2) #=>[2,3]

つまりこの

url = url.last(11)

で変数urlに格納されていたyoutube_urlの値のなかで最後の11桁の値のみを取り出し、改めて変数urlに格納するという処理をしています。

最後の三文目

@post.youtube_url = url

ここではviewで使用するインスタンス変数@postへ↑の変数urlの値を格納することでviewで@post.youtube_urlの値を呼び出すとvideo_idの値を返すようにします。

viewの処理

viewではposts/showおよびposts/indexページに埋め込みurlを用意しておきます。

posts/show.html.erb
<p id="notice"><%= notice %></p>

<p>
  <strong>Body:</strong>
  <%= @post.body %>
</p>

<p>
  <strong>Youtube url:</strong>
  <%= @post.youtube_url %>
</p>

<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>

上記の<%= @post.youtube_url %>の部分を以下のように書き換えます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/<%= @post.youtube_url%>" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

YouTubeの埋め込みurlを用意し末尾のvideo_idが入る部分に@post.youtube_urlの値が入るようにすることで、viewの中でどんなYouTubeURLが来ても埋め込み動画にするようにしています。

posts/index.html.erbも同様に

posts/index.html.erb
<% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.youtube_url %></td>
        <td><%= link_to 'Show', post %></td>
        <td><%= link_to 'Edit', edit_post_path(post) %></td>
        <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
<% end %>

の<%= post.youtube_url %>部分に以下のコードを代入します

<iframe width="560" height="315" src="https://www.youtube.com/embed/<%=post.youtube_url%>" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

これでこのように表示されていれば完璧です。

Qiita-gif3.gif

終わり

以上です。少し無理やりですが、YouTubeURLを投稿されたら埋め込み動画にするrailsアプリを作ってみました。

謝辞

ありがとうまこっちゃん

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】rails generate devise:install で terminal が止まる

現象

https://qiita.com/Hal_mai/items/350c400e8763ce0487a3

上記の記事を参考にdeviseを導入した際に、以下のコマンドを叩いた時に、 Railsコマンドが動かなくなった。

rails generate devise:install

解決策

Rails application preloader の spring を一旦停止させる。

bundle exec spring stop

参考

https://qiita.com/Hal_mai/items/350c400e8763ce0487a3
https://github.com/rails/spring

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Uncaught TypeError: Cannot read property 'observe' of undefined

Uncaught TypeError: Cannot read property 'observe' of undefined

mutation observerを使用するところでエラーが発生。
解決策:

$(document).ready(function () {~~~~の記述を追加する。
readyがないと動きませんでした。

参考:
https://codeday.me/jp/qa/20190416/639353.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者用競技プログラミングの入力方法まとめ(ruby)

はじめに

この記事は以下のruby初学者を想定しております
・rubyを使い始めて配列や繰り返し処理、ハッシュなどの概念を理解しているかた。
・paizaやAtcoderなどの競技プログラミングに興味があるけど問題で与えられた数値の適切な取り込み方がわからないかた。

私もはじめ与えられた数値が適切に取得できずに苦労したのでまとめを残しておきます。

1次元の数値の取り込み

整数一つの場合

10

という数値が与えられてそれを取得する場合は

N = gets.to_i
puts N
コンソール
10 :入力値

10 :出力値

上記のコンソール画面のように10を入力して10が出力されるはずです。

一列で複数の整数が与えられる場合

1 2 3 … s

上記のような数値間に半角スペースが数列を入力する場合は数列で取り込むのが簡単なやり方です。

N = gets.chomp.split.map(&:to_i)
puts N
コンソール
1 2 3 4 5 :入力値

1  :出力値



5 

コードの説明の説明をすると
chompは文字列の末尾の改行文字を取り除いた新しい文字列を返します。(これがないと半角スペースによる改行判定で先頭1文字しか入力できなくなってしまいます。)
splitは文字列を分割し、配列を返すメソッドです。
map(&:to_i)はおなじみの繰り返しメソッドですが末尾に(&:to_i)を宣言することでinteger 型で入力値を読み込めます。

配列を出力する場合、putsを用いると1文字ごとに改行して出力することに注意してください。

2次元の数値の取り込み

N K Q  :N K Qは全て整数
A1
A2
.
.
.
AQ :Aの横の数字はQ番目の数値という意味

上記のように一列目を取り込んだ後に、
1行ごとにQ個の数を入力する場合はやり方としては

N, K, Q = gets.chomp.split.map(&:to_i)
A = Q.times.map { gets.to_i }
puts A
コンソール
6 3 4  :入力値
3
1
3
2 

3 :出力値
1
3
2

これらの組み合わせができればある程度の問題までは対応できました。

文字列に関しても to_i を to_s に変えれば大丈夫です。

その他のテクニック(sortを使った並べ替え)

最後に使えると便利な小技として並べ替え(sort)の紹介をしたいと思います。

5 4 7 11 9 2 42 1

入力値として上記の数字の列を与えられて小さい順や大きい順に並べ替えたい時sortのメソッドを使うと便利です。(知らずに苦労してた時期も私にはありました。笑)

N = gets.chomp.split.map(&:to_i)
N.sort!
p N

N..sort! {|a, b| b <=> a }
p N
コンソール
5 4 7 11 9 2 42 1  :入力値
 
[1, 2, 4, 5, 7, 9, 11, 42]  :出力値
[42, 11, 9, 7, 5, 4, 2, 1]

コンソールを見てみると
1回目の出力で小さい順に並んでいて
2回目の出力で大きい順に並んでいます。

これらのテクを使えば競プロの簡単な問題は解けるようになるはずです。

私も競技プログラミング初心者ですが、一緒に頑張っていきましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Cloud9 に Ruby 2.5.0 と thinreports gem を インストールして Lambda で PDFを生成する方法

はじめに

AWS Cloud9 環境にて Rubyで作成した Lambda関数を Cloud9でzip圧縮→Lambdaにアップロードして動かすまでやってみました。

ポイントは下記の通り

  • LambdaのRubyランタイムと合わせる為に、Cloud9 に rvm で Ruby 2.5.0 をインストール
  • S3バケットにLambda関数からPDFファイルを書き込む為の権限設定

最終的に、[kintone] → [API Gateway] → [Lambda] → [PDF生成] → [/tmp保存] → [kintone添付ファイルに保存] までの予定ですが、まず [/tmp保存] まで実装します。

実装イメージ

今回はオレンジ色の範囲を実装します。

kintoneAwsLambdaThinreports.png

実行環境

  • AWS Cloud9
  • macOS 10.13.6
  • Ruby 2.5.0

処理の流れ

  1. Cloud9 に Ruby 2.5.0 をインストール
  2. kintoneアプリ作成→PDF生成処理の[Lambda]関数を実行する[API Gateway]を叩くJSを仕込みます
  3. PDF生成用のPDFレイアウトファイルの作成
  4. PDF生成用のLambda関数の作成
  5. S3バケットの権限設定
  6. S3バケットにPDFファイルを生成できることを確認
  7. /tmp にPDFファイルを保存

一旦前回の処理と同様にS3にPDFファイルを生成することが出来ることを確認してから、/tmpに保存してみたいと思います。

0.(事前準備)Cloud9 に Ruby 2.5.0 をインストール

(2019-10-25現在)Lambdaで実行される Rubyランタイム のバージョンは 2.5.0 です。
作成するライブラリやディレクトリ構成も合わせる必要があるので、Cloud9 に rvm を利用して Ruby 2.5.0 をインストールします。
また、今回必要なライブラリも bundler で プロジェクトディレクトリの下の vendoer/bundle にインストールします。(最終的にZipでまとめて Lambda にアップロードする為です)

rvm で Ruby 2.5.0 をインストール

ターミナルから rvm で Rubyをインストールしていきます。
rvm list で確認すると、現在は Ruby 2.6.0 がデフォルトでインストールされています。
rvm install ruby 2.5.0 で Ruby 2.5.0 をインストールします。

$ rvm list
=* ruby-2.6.3 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

$ rvm install 2.5.0
$ rvm install 2.5.0
Warning, new version of rvm available '1.29.9', you are using older version '1.29.8'.
You can disable this warning with:    echo rvm_autoupdate_flag=0 >> ~/.rvmrc
You can enable  auto-update  with:    echo rvm_autoupdate_flag=2 >> ~/.rvmrc
Searching for binary rubies, this might take some time.
No binary rubies available for: amazon/2018.03/x86_64/ruby-2.5.0.
Continuing with compilation. Please read 'rvm help mount' to get more information on binary rubies.
Checking requirements for amazon.
Requirements installation successful.
Installing Ruby from source to: /home/ec2-user/.rvm/rubies/ruby-2.5.0, this may take a while depending on your cpu(s)...
ruby-2.5.0 - #downloading ruby-2.5.0, this may take a while depending on your connection...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13.3M  100 13.3M    0     0  28.0M      0 --:--:-- --:--:-- --:--:-- 28.0M
ruby-2.5.0 - #extracting ruby-2.5.0 to /home/ec2-user/.rvm/src/ruby-2.5.0.....
ruby-2.5.0 - #applying patch /home/ec2-user/.rvm/patches/ruby/2.5.0/prelude_gcc_diagnostic.patch.
ruby-2.5.0 - #applying patch /home/ec2-user/.rvm/patches/ruby/2.5.0/libressl_2_7.patch.
ruby-2.5.0 - #configuring...................................................................
ruby-2.5.0 - #post-configuration..
ruby-2.5.0 - #compiling...................................................................................
ruby-2.5.0 - #installing.............................
ruby-2.5.0 - #making binaries executable..
ruby-2.5.0 - #downloading rubygems-3.0.6
ruby-2.5.0 - #extracting rubygems-3.0.6......
ruby-2.5.0 - #removing old rubygems........
ruby-2.5.0 - #installing rubygems-3.0.6...............................................
ruby-2.5.0 - #gemset created /home/ec2-user/.rvm/gems/ruby-2.5.0@global
ruby-2.5.0 - #importing gemset /home/ec2-user/.rvm/gemsets/global.gems................................................................
ruby-2.5.0 - #generating global wrappers.......
ruby-2.5.0 - #gemset created /home/ec2-user/.rvm/gems/ruby-2.5.0
ruby-2.5.0 - #importing gemsetfile /home/ec2-user/.rvm/gemsets/default.gems evaluated to empty gem list
ruby-2.5.0 - #generating default wrappers.......
ruby-2.5.0 - #adjusting #shebangs for (gem irb erb ri rdoc testrb rake).
Install of ruby-2.5.0 - #complete 
Please be aware that you just installed a ruby that requires 2 patches just to be compiled on an up to date linux system.
This may have known and unaccounted for security vulnerabilities.
Please consider upgrading to ruby-2.6.3 which will have all of the latest security patches.
Ruby was built without documentation, to build it run: rvm docs generate-ri
admin-user:~/environment $ rvm list
=> ruby-2.5.0 [ x86_64 ]
 * ruby-2.6.3 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]

bundle install で aws-sdk-s3, thinreports をインストール

Ruby 2.5.0 がインストールされ利用できる様になりました。
次は以下の2つのRubyライブラリをインストールします。

プロジェクトのディレクトリに移動して、
bundle init
出来たGemfileに追記

gem 'thinreports'
gem 'aws-sdk-s3', '~> 1'

bundle install を実行します

$ bundle install
Fetching gem metadata from https://rubygems.org/...............
Resolving dependencies...
Fetching aws-eventstream 1.0.3
Installing aws-eventstream 1.0.3
Fetching aws-partitions 1.228.0
Installing aws-partitions 1.228.0
Fetching aws-sigv4 1.1.0
Installing aws-sigv4 1.1.0
Fetching jmespath 1.4.0
Installing jmespath 1.4.0
Fetching aws-sdk-core 3.72.0
Installing aws-sdk-core 3.72.0
Fetching aws-sdk-kms 1.25.0
Installing aws-sdk-kms 1.25.0
Fetching aws-sdk-s3 1.51.0
Installing aws-sdk-s3 1.51.0
Using bundler 1.17.3
Fetching pdf-core 0.7.0
Installing pdf-core 0.7.0
Fetching ttfunk 1.5.1
Installing ttfunk 1.5.1
Fetching prawn 2.2.2
Installing prawn 2.2.2
Fetching thinreports 0.10.3
Installing thinreports 0.10.3
Bundle complete! 2 Gemfile dependencies, 12 gems now installed.
Bundled gems are installed into `./vendor/bundle`

ディレクトリ構成確認

プロジェクトディレクトリは下記の構成になっています。

|--hello-world.rb
|--hello_world.tlf
|--kintoneToPdf
| |--index.js
|--template.yaml
|--vendor
| |--bundle
| | |--ruby
| | | |--2.5.0
| | | | |--bin
| | | | |--build_info
| | | | |--cache
| | | | |--doc
| | | | |--extensions
| | | | |--gems

| | | | | |--aws-sdk-s3-1.51.0
| | | | | | |--lib
| | | | | | | |--aws-sdk-s3
| | | | | | | | |--bucket_acl.rb
| | | | | | | | |--bucket_cors.rb
| | | | | | | | |--bucket_lifecycle_configuration.rb
| | | | | | | | |--bucket_lifecycle.rb
| | | | | | | | |--bucket_logging.rb
| | | | | | | | |--bucket_notification.rb
| | | | | | | | |--bucket_policy.rb
| | | | | | | | |--bucket.rb
| | | | | | | | |--bucket_region_cache.rb

| | | | | |--thinreports-0.10.3
| | | | | | |--CHANGELOG.md
| | | | | | |--fonts
| | | | | | |--Gemfile
| | | | | | |--lib
| | | | | | | |--thinreports
| | | | | | | | |--config.rb
| | | | | | | | |--core

vendor/bundle/ruby/2.5.0/gems 以下に aws-sdk-s3, thinreports の Ruby gems(ライブラリ) がインストールされました。

1. kintoneアプリ作成

次の拙稿の記事を参考にして下さい。
https://qiita.com/sy250f/items/0f2aaf17fd670bf82c84#kintone%E3%82%A2%E3%83%97%E3%83%AA%E4%BD%9C%E6%88%90

2. Thinreportsレイアウトファイルの作成

ThinreportsThinreports Editorを使って作成したレイアウトファイルをテンプレートとして、PDFを生成します。

次の拙稿の記事を参考にして下さい。
https://qiita.com/sy250f/items/0f2aaf17fd670bf82c84#thinreports%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90

作成したレイアウトファイルは、後ほど Zip圧縮するためにCloud9のプロジェクトディレクトリにアップロードしておきます。

3. AWS Lambad for Ruby と Thinreports によるPDF出力

前段の記事では、ローカルの mac環境で作成したプログラムをZipにしてLambdaにアップロードしていました。
今回は Cloud9環境 で Lambda を作成してデプロイしてみます。

Cloud9 から Lambdaアプリの作成

新しく Lambdaアプリを作成していきます。
λ+(create new lambda function)ボタンから作成していきます。下記スクリーンショットを参考にしてください。

1.λ+ボタン押下
スクリーンショット 2019-10-24 9.37.02.png

2.ファイル名、アプリ名入力(ディレクトリは アプリ名/ファイル名/ になります)
スクリーンショット 2019-10-24 9.33.49.png

3.blueprintの選択に Ruby が無いのでとりあえず Node.js を選びます。
スクリーンショット 2019-10-24 9.34.23.png

4.API Gateway の設定をします。
スクリーンショット 2019-10-24 9.34.55.png

5.ロールは自動作成にします。
後ほどS3の権限も合わせて調整します。
スクリーンショット 2019-10-24 9.35.07.png

Ruby にて Lambda関数 の作成

Ruby にて Lambda関数を作成します。

コードは拙稿を参考ください。
https://qiita.com/sy250f/items/0f2aaf17fd670bf82c84#lambda%E3%83%95%E3%82%A1%E3%83%B3%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90

Lambdaアプリの直下のディレクトリに右クリックして [hello_world.rb] を作成します。
コードは上記をそのままコピーします。
スクリーンショット 2019-10-24 10.03.46.png

zipファイル作成

Lambdaの実行に必要なファイルをzip圧縮します。
必要なファイルとフォルダは下記の通り。

  • hello-world.rb(プログラム本体)
  • hello_world.tlf(Thinreports Editor で作成したレイアウトファイル)
  • vendor(gemファイルのディレクトリ)

zip -r アーカイブファイル名 圧縮するファイルやディレクトリをスペース区切りで指定。

詳しくは man zip にて確認してください。

$ ls -la
total 42076
drwxr-xr-x 6 ec2-user ec2-user     4096 Oct 26 01:21 .
drwxr-xr-x 8 ec2-user ec2-user     4096 Oct 24 00:35 ..
-rw-r--r-- 1 ec2-user ec2-user      349 Oct 24 02:26 .application.json
drwxrwxr-x 2 ec2-user ec2-user     4096 Oct 24 02:55 .bundle
-rw-r--r-- 1 ec2-user ec2-user      189 Oct 25 15:57 Gemfile
-rw-rw-r-- 1 ec2-user ec2-user      784 Oct 26 00:19 Gemfile.lock
drwxrwxr-x 8 ec2-user ec2-user     4096 Oct 24 01:15 .git
-rw-r--r-- 1 ec2-user ec2-user       34 Oct 24 02:53 .gitignore
-rw-r--r-- 1 ec2-user ec2-user     1498 Oct 25 09:23 hello-world.rb
-rw-r--r-- 1 ec2-user ec2-user    56945 Oct 24 13:07 hello_world.tlf
drwxr-xr-x 2 ec2-user ec2-user     4096 Oct 24 22:24 kintoneToPdf
-rw-r--r-- 1 ec2-user ec2-user      841 Oct 24 06:15 template.yaml
drwxrwxr-x 3 ec2-user ec2-user     4096 Oct 26 00:19 vendor

$ zip -r hello-world.zip hello-world.rb hello_world.tlf vendor

$ ls -la
total 42076
drwxr-xr-x 6 ec2-user ec2-user     4096 Oct 26 01:21 .
drwxr-xr-x 8 ec2-user ec2-user     4096 Oct 24 00:35 ..
-rw-r--r-- 1 ec2-user ec2-user      349 Oct 24 02:26 .application.json
drwxrwxr-x 2 ec2-user ec2-user     4096 Oct 24 02:55 .bundle
-rw-r--r-- 1 ec2-user ec2-user      189 Oct 25 15:57 Gemfile
-rw-rw-r-- 1 ec2-user ec2-user      784 Oct 26 00:19 Gemfile.lock
drwxrwxr-x 8 ec2-user ec2-user     4096 Oct 24 01:15 .git
-rw-r--r-- 1 ec2-user ec2-user       34 Oct 24 02:53 .gitignore
-rw-r--r-- 1 ec2-user ec2-user     1498 Oct 25 09:23 hello-world.rb
-rw-r--r-- 1 ec2-user ec2-user    56945 Oct 24 13:07 hello_world.tlf
-rw-rw-r-- 1 ec2-user ec2-user 42976393 Oct 26 01:21 hello-world.zip
drwxr-xr-x 2 ec2-user ec2-user     4096 Oct 24 22:24 kintoneToPdf
-rw-r--r-- 1 ec2-user ec2-user      841 Oct 24 06:15 template.yaml
drwxrwxr-x 3 ec2-user ec2-user     4096 Oct 26 00:19 vendor

出来たzipファイルはzipファイル上で右クリック→ダウンロードを選択して、ローカルへダウンロードします。

4. Lambda 及び S3 バケットへの権限設定

S3に書き込み権限を付与した[IAM]を作成して、LambdaにIAMを設定します。
また、S3バケットに作成した[IAM]にてオブジェクト(今回はPDF)を書き込める様に設定します。

下記の図の様に権限設定を行います。

s3_read_write_setting.png

IAM ポリシー

Lambdaの実行ポリシーとS3バケットの書き込み権限を付けます。

Lambdaの実行権限を付与

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

S3への書き込み権限を付与

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::S3バケット名/*"
        }
    ]
}

S3バケットの権限設定

{
    "Id": "Policy9999999999",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt9999999999",
            "Action": [
                "s3:PutObject"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::バケット名",
                "arn:aws:s3:::バケット名/*"
            ],
            "Principal": {
                "AWS": [
                    "arn:aws:iam::Lambdaに設定したIAMロール"
                ]
            }
        }
    ]
}

5. S3バケットに生成したPDFの出力を確認する

kintoneアプリに設置したボタンをクリックしてLabmdaを実行し、S3にPDFが生成されていることを確認します。

S3バケットにzipファイルをアップロード

S3ファイルのURLをコピーします。
スクリーンショット 2019-10-26 11.25.26.png

LambdaにS3のzipファイルをアップロード

関数コードをS3からアップロードします。先ほどコピーしたURLを貼り付けます。
スクリーンショット 2019-10-26 11.25.00.png

kintoneアプリからLambdaを実行

kintoneアプリから実行します。
スクリーンショット 2019-10-26 11.32.37.png

PDFファイルの生成を確認

バケットを確認します。
スクリーンショット 2019-10-26 11.34.06.png

PDFファイルを開いて中身を確認します。
スクリーンショット 2019-10-26 11.33.42.png

6. /tmp ディレクトリにPDF出力

コードを編集して、Lambda の /tmp ディレクトリにPDFを出力してみます。

hello_world.rb
# coding: utf-8
require 'thinreports'
require 'json'
require 'aws-sdk-s3'

def lambda_handler(event:, context:)
    begin
        print 'JSON.parse event.body => '
        pp JSON.parse(event["body"])
        event_body = JSON.parse(event["body"])
        record = event_body["record"]
        print 'record => '
        pp record
        puts '$id => ', record["$id"]["value"]
        puts 'text => ', record["text"]["value"]
    rescue => e
        puts "#{e.class}: #{e.message}"
        puts e.backtrace
    end

    begin
        region = 'S3バケットのリージョン'
        bucket_name = 'バケット名'
        key = 'put-hello-ruby.pdf'
        # S3 Backet Object init
        s3 = Aws::S3::Resource.new(region: region)
        obj = s3.bucket(bucket_name).object(key)
        report = Thinreports::Report.new layout: 'hello_world'
        # 1st page
        report.start_new_page
        report.page.item(:world).value(record["$id"]["value"])
        report.page.item(:thinreports).value(record["text"]["value"])
        obj.put(body: report.generate)

        # /tmpファイルに書き込み
        filename = '/tmp/put-hello-ruby-' + Time.new.localtime("+09:00").strftime("%Y%m%d%H%M%S") + '.pdf'
        puts filename
        File.open(filename, 'w+') { |f| f<< report.generate }
        puts `ls -la /tmp`
    rescue => e
        puts "#{e.class}: #{e.message}"
        puts e.backtrace
    end

    { statusCode: 200, body: JSON.generate('Hello Lambda! Thinreports for Ruby') }
end

ログの表示

JSON.parse event.body => {"type"=>"app.record.detail.show",
"appId"=>219,
"recordId"=>3,
"record"=>
{"レコード番号"=>{"type"=>"RECORD_NUMBER", "value"=>"3"},
"更新者"=>
{"type"=>"MODIFIER", "value"=>{"code"=>"aaaaa", "name"=>"アプリ管理者"}},
"作成者"=>{"type"=>"CREATOR", "value"=>{"code"=>"aaaaa", "name"=>"アプリ管理者"}},
"更新日時"=>{"type"=>"UPDATED_TIME", "value"=>"2019-10-26T05:01:00Z"},
"作成日時"=>{"type"=>"CREATED_TIME", "value"=>"2019-10-26T05:01:00Z"},
"text"=>{"type"=>"SINGLE_LINE_TEXT", "value"=>"/tmp に保存"},
"$revision"=>{"type"=>"__REVISION__", "value"=>"1"},
"$id"=>{"type"=>"__ID__", "value"=>"3"}}}
record => {"レコード番号"=>{"type"=>"RECORD_NUMBER", "value"=>"3"},
"更新者"=>{"type"=>"MODIFIER", "value"=>{"code"=>"aaaaa", "name"=>"アプリ管理者"}},
"作成者"=>{"type"=>"CREATOR", "value"=>{"code"=>"aaaaa", "name"=>"アプリ管理者"}},
"更新日時"=>{"type"=>"UPDATED_TIME", "value"=>"2019-10-26T05:01:00Z"},
"作成日時"=>{"type"=>"CREATED_TIME", "value"=>"2019-10-26T05:01:00Z"},
"text"=>{"type"=>"SINGLE_LINE_TEXT", "value"=>"/tmp に保存"},
"$revision"=>{"type"=>"__REVISION__", "value"=>"1"},
"$id"=>{"type"=>"__ID__", "value"=>"3"}}
$id =>
3
text =>
/tmp に保存
/tmp/put-hello-ruby-20191026143607.pdf
total 56
drwx------ 2 sbx_user1051 495 4096 Oct 26 05:36 .
dr-xr-xr-x 21 root root 4096 Sep 24 18:18 ..
-rw-rw-r-- 1 sbx_user1051 495 49084 Oct 26 05:36 put-hello-ruby-20191026143607.pdf

/tmp フォルダにPDFが出力されました。


あとがき

昨日(2019-10-25 Fri)、JAWS-UG浜松 というAWSのユーザー会に参加しました。
今回は参加された方がそれぞれ発表する会の様で、サーバーレスで顔認識するWebアプリの話(Vue,Lambda,Python,DynamoDB,Amplify,AppSync,KMS,OpenCVなど利用)。サーバーレスでブログを作った話(Vue,Python,Lambda,Cognitoなど)。AWSとラズパイで工場にMESを導入した話。などなどとても刺激になる話が聞けてモチベーションだけは高まりました。特にAWSとラズパイの話は興味深かったです。ラズパイを工場のラインに設置して工作機械からの信号をラズパイで受けて3G回線で[AWS IoT]へ送り、CloudWatch,Athena,Kinesis,QuickSightなどで分析してリアルタイムで工場のラインの出来高や稼働率をダッシュボードで表示。工場の異常はビデオで撮影。またデータはDynamoDBに保存。ラズパイを使ったハード回りやプログラミングも全て一人で行ったというのがすごかった。
CloudWathもBIとして使えるなど、AWSのサービスは知らないことが多いなと思いました。
今後も定期的にJAWS-UGに参加したいです。懇親会も楽しかった。

今後やりたいこと

下記のサービスを触ってみたいと思います。


参考リンク

AWS関連

Ruby関連

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CatalinaでSassがインストールできないとき試したこと。

最初に

先日初めてMacbookを購入しSassを導入しようとしたときに
かなり手こずってしまったので備忘録としてここに残します。

よく見かける方法

MacにははじめからRubyがインストールされているため、
特別な準備などはいらず、ターミナルに以下のコードを入力するだけ

$ gem install sass

などとよく書かれているのを目にするのですが

ERROR: While executing gem ... (Gem::FilePermissionError)
You don't have write permissions for the /Library/Ruby/Gems/2.6.0 directory

書き込み権限がないため当然このようなテキストが返されます。
どうもこれ、OS X 10.11 El Capitanからのようで/usrや/binなどの
ディレクトリにアクセスできないようになっているとかで。

ディレクトリを変えてみる

どうにもできないと思って
検索をかけてみたところアクセスができないなら別のディレクトリに
入れれば大丈夫!との記事を見つけたため実践。

$ sudo gem install sass -n /usr/local/bin/

さあこれで…と思いきやまたエラー。

スクリーンショット 2019-10-24 11.27.31.png
rubyは間違いなく入ってるので正直エラーの原因がわからない…

首をかしげながらいろんな記事を読んでは施行するも
結局は同じような内容なのでかわらず。

突然の解決

きっとこれも違うだろうなと思いながら検索して出てきた文字を入力。
そしていつものようにパスワードをっと…

$ sudo gem install -n /usr/local/bin sass

スクリーンショット 2019-10-26 12.37.43.png

あれ、なんか反応が違う…
エラーが返ってこない!
これはもしやインストールできたのでは…!!と試しにバージョンを確認。

$ sass -v

Ruby Sass 3.7.4

終わった…
Rubyをアップデートするために四苦八苦してみたことが
役に立ったのかそれとも上記のコードを
試した結果なのかは定かではありませんがなんとかなりました。

最後に

一応下記に自分が試したものを掲載して終わりにしようと思います。

https://github.com/ffi/ffi/issues/651#issuecomment-538723566
(4のRVM導入で躓いたので途中までですが)

検証もままならないような覚書で申し訳ありませんが、
お役に立てれば幸いです。

また、実際に試してみた方や間違いがあれば
コメントいただければありがたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-composeでBundler::GemNotFoundになる

docker-composeでBundler::GemNotFoundになる

たまに起こって毎回アレッって思うのでメモ

docker-compose upするとGemNotFound

railsプロジェクトで、いつも通りdocker-compose upをすると、たまにBundler::GemNotFoundのエラーとなり起動できないことがある。

bundle installしても解決はしない

docker-compose build しなおす

docker-compose build でビルドしなおし、再度docker-compose upをすると正常に起動する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】Google Map APIの導入

はじめに

つくるもの

Google Map APIを導入しページに地図を表示させます。
今回は検索した住所にピンを立て、そこの緯度経度を表示させるまでを実装します。

gmap-step0.gif

コードを書く前に

Google Maps API を利用するには、API キーという許可証のようなものを取得する必要があります。
API キーを取得する為にGoogle アカウントが必要になるので、事前に準備しておきましょう。

Google アカウントの作成はこちらから

そしてGoogle Cloud Platformへアクセスして、APIキーを取得しましょう。

プロジェクトの作成

gmap-01.png

gmap-02.png

gamp-03.png

gmap-04.png

APIの有効化

gmap-05.png

gamp-06.png

APIキーの作成

gmap-07.png

gmap-08.png

gmap-09.png

gmap-10.png

gmap-11.png

gmap-12.png

gmap-13.png

gmap-14.png

gmap-15.png

gmap-17.png

移行ツール

課金設定をしていないと、いざ地図を表示しようとしてもエラーが出てしまいます。
エラー文は以下の通りです。
You have exceeded your request quota for this API.
See https://developers.google.com/maps/documentation/javascript/error-messages?utm_source=maps_js&utm_medium=degraded&utm_campaign=billing#api-key-and-billing-errors

移行ツール にアクセスし、手順にしたがって登録します。

アプリケーション作成

長きにわたる諸々の設定おつかれさまでした。
ここから早速アプリケーションを作っていきましょう。

ファイルを作成する前に先ほど作成したAPIキーを用意しておいてください。

登場人物

今回作成・編集するページは

  • routes.rb
  • maps_controller.rb
  • index.html.erb

この3つです。それぞれのファイルに書き込んでください。

ルーティング

routes.rb
Rails.application.routes.draw do
  get 'maps/index'
  root to: 'maps#index'
  resources :maps, only: [:index]
end

コントローラー

maps_controller.rb
class MapsController < ApplicationController
  def index
  end
end

ビューページ

マップ完成イメージ.png

ビュー作成

地図を表示させる

では以下のコードをファイルにコピーしてみましょう。

index.html.erb
<h2>gmap</h2>
<div id='map'></div>

<style>
#map {
  height: 600px;
  width: 600px;
}
</style>

<script>
let map

function initMap(){
  geocoder = new google.maps.Geocoder()

  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 40.7828, lng:-73.9653},
    zoom: 12,
  });

  marker = new google.maps.Marker({
    position:  {lat: 40.7828, lng:-73.9653},
    map: map
  });
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script>

<style>タグでマップの大きさを指定していますが、ここを省いてしまうと地図が表示されないので必ず書きましょう。

<style>#map {height: 600px;width: 600px;}</style>

次に地図の初期設定についてですが、 centerで初期位置の緯度経度を指定し、 zoomで表示領域の大きさを決めます。

function initMap(){
  geocoder = new google.maps.Geocoder()

  map = new google.maps.Map(document.getElementById('map'), {
    //latが緯度、lngが経度を示します
    center: {lat: 40.7828, lng:-73.9653},
    //数値は0〜21まで指定できます。数値が大きいほど拡大されます
    zoom: 12,
  });
  //positionに指定した座標にピンを表示させます
  marker = new google.maps.Marker({
    position:  {lat: 40.7828, lng:-73.9653},
    map: map
  });
}

そして最後の行の YOUR_API_KEYの部分に自分で作成したキーを入れてください。

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script>

ではここで実際にブラウザで地図が表示されるか確認してみましょう。
以下のように表示されたでしょうか?

gmap-step1.png

検索フォームから住所を特定しピンを刺す

次に検索フォームを作成します。

index.html.erb
<h2>gmap</h2>

<!-- ここから追加 -->
<input id="address" type="textbox" value="GeekSalon">
<input type="button" value="Encode" onclick="codeAddress()">
<!-- ここまで追加-->

<div id='map'></div>

<style>
#map {
  height: 600px;
  width: 600px;
}
</style>

<script>
let map
function initMap(){
  geocoder = new google.maps.Geocoder()

  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 40.7828, lng:-73.9653},
    zoom: 12,
  });

  marker = new google.maps.Marker({
    position:  {lat: 40.7828, lng:-73.9653},
    map: map
  });
}
// ここから追加 
let geocoder

function codeAddress(){
  let inputAddress = document.getElementById('address').value;

  geocoder.geocode( { 'address': inputAddress}, function(results, status) {
    if (status == 'OK') {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location
      });
    } else {
      alert('該当する結果がありませんでした:' + status);
    }
  });   
}
// ここまで追加 
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script>

2箇所追加しました。
ビューに関する部分では検索フォームとボタンを作成しました。

<input id="address" type="textbox" value="GeekSalon">
<input type="button" value="Encode" onclick="codeAddress()">

次に <script>タグ内に検索機能の処理を追加しました。

let geocoder

  //検索フォームのボタンが押された時に実行される
function codeAddress(){
  //検索フォームの入力内容を取得
  let inputAddress = document.getElementById('address').value;

  geocoder.geocode( { 'address': inputAddress}, function(results, status) {
    //該当する検索結果がヒットした時に、地図の中心を検索結果の緯度経度に更新する
    if (status == 'OK') {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location
      });
    } else {
      //検索結果が何もなかった場合に表示
      alert('該当する結果がありませんでした:' + status);
    }
  });   
}

では早速ブラウザを開いて見てみましょう。
以下のように検索結果に応じて結果が処理される機能をつけました。

gmap-step2.gif

検索結果から緯度経度を取得し、表示させる

さて初めてのGoogleマップ講座もいよいよ大詰めです。
最後に検索結果の緯度経度をページに表示させましょう。

コードは以下の通りです。

index.html.erb
<h2>gmap</h2>

<input id="address" type="textbox" value="GeekSalon">
<input type="button" value="Encode" onclick="codeAddress()">
<!-- 下の1行を追加 -->
<div id="display">何かが表示される、、、、!</div>

<div id='map'></div>

<style>
#map {
  height: 600px;
  width: 600px;
}
</style>

<script>
let map
let geocoder
// 下の1行を追加 
const display = document.getElementById('display')

function initMap(){
  geocoder = new google.maps.Geocoder()

  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 40.7828, lng:-73.9653},
    zoom: 12,
  });

  marker = new google.maps.Marker({
    position:  {lat: 40.7828, lng:-73.9653},
    map: map
  });
}

function codeAddress(){
  let inputAddress = document.getElementById('address').value;

  geocoder.geocode( { 'address': inputAddress}, function(results, status) {
    if (status == 'OK') {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location
      });
      // 下の1行を追加 
      display.textContent = "検索結果:" + results[ 0 ].geometry.location
    } else {
      alert('該当する結果がありませんでした:' + status);
    }
  });   
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB9Uo-0D2PoQaAECrt9UXceHO7S1gveNd0&callback=initMap" async defer></script>

ビューに関して1箇所、 <script>タグ内に2箇所追加しました。
それぞれ追加する場所を確認し、追加して見てください。
追加した要素・処理は

  • 検索結果を表示させるためのディスプレイ
  • ディスプレイの情報を取得
  • 検索結果をディスプレイに表示

の3つです。なので追加箇所も3箇所です。
これでコードの書き込みは完了です。

ではでは最後にブラウザを開いて確認してみましょう。
検索結果がディスプレイに表示されれば完成です。

gmap-step3.gif

次回に続く!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自分用メモ:rbenvとruby_buildをインストールしてrubyをインストールする手順でハマった話

ハマった話シリーズ。

やりたいこと

・特定のユーザにのみrubyをインストールさせたい
・rubyのインストールにはrbenvとruby_buildを用いたい
・インターネットアクセスせず完全ローカル上で完結させたい
・すべてansible playbookで自動化すること

ディレクトリ構成

├── roles
│   └──middle
│      └── ruby
│          └── files
│          │   └── opt
│          │       └── node1
│          │       │   └── .bash_profile
│          │       │   └── .rbenv # rbenvとruby_buildのzipパッケージはここに配置する
│          │       │       └── plugins # 必要なrpmはすべてここに格納
│          │       └── node2
│          │           └──以下node1と同一構成
│          └── tasks
│              └── main.yml
└── vars
    └── middle_var.yml
    └── usr_var.yml

※rubyに関係する箇所以外のnode情報は他で記述しているためここでは割愛

参考

https://qiita.com/inouet/items/478f4228dbbcd442bfe8

その他情報

・OSはCentOS7.4
・rubyはデフォルトでは2.0.0がインストールされている

手順概要

1.グループ作成
2.ユーザーアカウント作成
3.ソースディレクトリ作成
4.ruby依存パッケージを事前にインストール
5.rbenvインストール
6.ruby_buildインストール
7..bash_profile配布と編集
8.シェルとソースのリフレッシュ
9.rubyインストール
10.rubyバージョン切り替え

手順詳細

※ここではnode1とnode1_usrのみ記述するが、node2_usrも同様にymlに記述すること

1.グループ作成
usr_var.ymlでよしなに記述してある前提で書くので変数の個所は割愛

- name: ■ アカウント一覧 - Group
  group: 
    name: "{{ item.group }}"
    gid: "{{ item.gid }}"
  with_items:
    - "{{ node1_usr }}"

node2_usrも同様に記述する。

2.ユーザーアカウント作成

- name: ■ アカウント一覧 - ユーザ
  user:
    #state: absent #ユーザを削除するときはコメントを外す
    name: "{{ item.name }}"
    uid : "{{ item.uid }}"
    password: "{{ item.password | password_hash('sha512') }}"    #変数からパスワード情報を取得し、ハッシュ化してパスワードを設定
    group:  "{{ item.group }}"
    home :  "{{ item.home }}"
    shell: /bin/bash
    update_password: on_create    #ユーザ作成時パスワード設定
  with_items:
    - "{{ node1_usr }}"
  no_log: True #パスワード、マスク
  when: node1_usr #postgres_user

3.ソースディレクトリ作成

- name: ■ ソース用ディレクトリ作成
  file: path={{ item.path }} owner={{ item.owner }} group={{ item.group }} mode={{ item.mode }} state=directory
  with_items:
    - { path: "/opt/node1_usr/"          , owner: node1_usr , group: node1_usr , mode: "755" }
    - { path: "/opt/node1_usr/.rbenv/"         , owner: node1_usr , group: node1_usr , mode: "755" }
    - { path: "/opt/node1_usr/.rbenv/plugins/" , owner: node1_usr , group: node1_usr , mode: "755" }

4.ruby依存パッケージを事前にインストール
対象rpmは以下の通り
-bison.rpm
-bzip2.rpm"
-m4.rpm
-ncurses-devel.rpm
-readline-devel.rpm

バージョンは割愛。
後ほどインストールするrubyファイルもここで配布しておく。
-ruby.tar.bz2 ruby公式からダウンロード

上記ファイルはまとめてrpmのフォルダに入れておく。

- name: ■ ruby RPM Copy
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
  with_items:
    - "{{ node1_rpm_cp }}"
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ ruby RPM Install
  yum:
    name: "{{ node1_rpm_install }}"
    state: present
  ignore_errors: "{{ ansible_check_mode }}"

node1_rpm_cpは配置したファイルをローカルに引っ張ってくる。
node1_rpm_installはruby依存rpmのみ先にインストールする。

5.rbenvインストール
インストールといってもzipファイルを解凍するだけ。
-rbenvmaster.zip githubからダウンロード
→適当なフォルダに配置

- name: ■ rbenv Source File Copy
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
  with_items:
    - "{{ rbenv_source_cp }}"
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ rbenv Source Unzip node1_usr
  command: chdir=/opt/node1_usr/.rbenv/ unzip -o rbenv-master.zip
  ignore_errors: "{{ ansible_check_mode }}"

ここは変数を入れ込むとバグるらしい、、、原因不明、、、

6.ruby_buildインストール
5同様4で配置したzipファイルを解凍するだけ。
-ruby-build-master.zip githubからダウンロード
→適当なフォルダに配置

- name: ■ ruby_build Source File Copy
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
  with_items:
    - "{{ ruby_build_source_cp }}"
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ ruby_build Source Unzip node1_usr
  command: chdir=/opt/node1_usr/.rbenv/plugins/ unzip -o ruby-builder-master.zip
  ignore_errors: "{{ ansible_check_mode }}"

7.rubyに必要なファイルの配布
.bash_profile を/opt/node1_usr/に配布する。
以下の通り編集する。最後の2行が大事。

# User specific environment and startup programs

PATH=$PATH:$HOME/bin
export PATH



export PATH="/opt/node1_usr/.rbenv/rbenv-master/bin:$PATH"
eval "$(rbenv init -)"

8.シェルとソースのリフレッシュ

- name: ■ Shell Refresh node1_usr
  become: yes
  become_user: node1_usr
  shell: exec $SHELL -l
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ .bash_profile Check Action node1_usr
  become: yes
  become_user: node1_usr
  shell: source ~/.bash_profile
  ignore_errors: "{{ ansible_check_mode }}"

9.rubyインストール
必要なバージョンがインストールされているかをまず確認する。
インストールされている場合はスキップする処理、されていない場合はインストールを続行する処理とする。

- name:  ■ Ruby Version Check Before Install node1_usr
  become: yes
  become_user: node1_usr
  stat: path=/opt/node1_usr/.rbenv/versions/n.n.n
  register: result

- name: ■ Ruby Install node1_usr
  become: yes
  become_user: node1_usr
  shell: bash -lc "RUBY_BUILD_CACHE_PATH=/opt/node1_usr/.rbenv/plugins/ rbenv install n.n.n"
  when: not result.stat.exists

10.rubyバージョン切り替え

- name: ■ Ruby Version Change node1_usr
  become: yes
  become_user: node1_usr
  shell: bash -lc "rbenv global n.n.n"
  ignore_errors: "{{ ansible_check_mode }}"

以上のコードはroles/middle/ruby/tasks/main.ymlに記述すること。

ハマった箇所と理由

5.rbenvインストール
コマンドを実行する箇所に変数を指定するとそんなファイル・パスはないと言われてしまう。
詳細は不明だが、絶対パスで書くのが無難。

6.ruby_buildインストール
5同様の注意事項。
ファイル名が似ているため、middle_var.ymlに書くときは注意。
ずっとruby_buildのインストールにrbenv-master.zipを指定していたことに気が付くのに時間がかかったのは自分だけでいい。

7.rubyに必要なファイルの配布
予め/opt/node1_usr/内に作っておくのが無難。
改行コードが問題になることがあるので、LFで統一すること。
CRLFで何時間もハマった。

8.シェルとソースのリフレッシュ
そこまで大ハマりしたわけではないが、シェルとソースのリフレッシュはansibleを実行するユーザではなくrubyをインストールするユーザを指定すべき。
これを避けるためにはbecome変数を使用し、bash -lcでコマンドを実行すること。

9.rubyインストール
インストール済みの場合スキップ、未インストールの場合のみインストールという処理を考えるとき、条件に悩んだ。
ruby -vでバージョンを出してもよかったが、バージョンの数値のみ取得するのが骨が折れそうだった。
rubyのインストールディレクトリ配下のversionというディレクトリの配下にバージョン名でディレクトリができることを利用し、
このディレクトリをインストールしたいバージョンの番号の有無と判定することにした。registerとwhen変数がそれである。
また、rbenv install n.n.n(バージョン名)でrubyをインストールする場合、何も指定しないとWeb上のファイルを取得しに行ってしまう。
予めダウンロード・配置しておいたファイルを使用してインストールする場合には、RUBY_BUILD_CACHE_PATH で配置先のディレクトリを指定してやる必要があった。

以上の工程に3人日使ってしまい非常にもったいないことをしたので備忘録としておく。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu 18.04 Railsインストールコマンド$ gem install rails のエラーを解決した話

目的

  • Ubuntu 18.04でコマンド$ gem install railsを実行した際に出たエラーを解決した話をまとめる。

経緯

  1. 下記記事を参考にUbuntu18.04でRailsの環境構築をしていたところ、コマンド$ gem install railsを実行した際にエラーが出た。
    MacOS / Ubuntu で Ruby on Rails の開発環境を構築する

エラー内容

  • 下記にエラー内容を抜粋した内容を記載する。
$ gem install rails
Building native extensions. This could take a while...
ERROR:  Error installing rails:
        ERROR: Failed to build gem native extension.

    current directory: /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/nokogiri-1.10.4/ext/nokogiri
/home/linuxbrew/.linuxbrew/opt/ruby/bin/ruby -I /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0 -r ./siteconf20191025-8352-1g8if1f.rb extconf.rb
checking if the C compiler accepts ... yes
Building nokogiri using packaged libraries.
Using mini_portile version 2.4.0
checking for gzdopen() in -lz... no
zlib is missing; necessary for building libxml2
*** extconf.rb failed ***
・
・
・
extconf failed, exit code 1

Gem files will remain installed in /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/nokogiri-1.10.4 for inspection.
Results logged to /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/nokogiri-1.10.4/gem_make.out

分析

  • エラーの内容を翻訳して見た。
  • どうやらzlibなるものがインストールされていないようだ。
# 翻訳前
checking for gzdopen() in -lz... no
zlib is missing; necessary for building libxml2
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary

# 翻訳語
-lzでgzdopen()をチェックしています... no
zlibがありません。 libxml2のビルドに必要
*** extconf.rbが失敗しました***
何らかの理由でMakefileを作成できませんでした。おそらく必要なものがありません。

解決方法

  • zlibをインストールする為のコマンド$ sudo apt-get install zlib1g-devを実行した。
  • 実行後再度コマンド$ gem install railsを実行したら正常に実行された。
  • 下記に解決方法に至った筆者の流れを記載する。
    1. コマンド$ gem install railsを実行したらエラー発生した。
    2. コマンド$ sudo apt-get install zlib1g-devを実行した。
    3. コマンド$ gem install railsが正常に実行できた。

付録

  • 下記に筆者がコマンド$ gem install railsでエラーを出してから解決するまでのログを記載する。
miriwo@miriwoPC:~$ gem install rails
Building native extensions. This could take a while...
ERROR:  Error installing rails:
        ERROR: Failed to build gem native extension.

    current directory: /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/nokogiri-1.10.4/ext/nokogiri
/home/linuxbrew/.linuxbrew/opt/ruby/bin/ruby -I /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0 -r ./siteconf20191025-8352-1g8if1f.rb extconf.rb
checking if the C compiler accepts ... yes
Building nokogiri using packaged libraries.
Using mini_portile version 2.4.0
checking for gzdopen() in -lz... no
zlib is missing; necessary for building libxml2
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/bin/$(RUBY_BASE_NAME)
        --help
        --clean
        --use-system-libraries
        --enable-static
        --disable-static
        --with-zlib-dir
        --without-zlib-dir
        --with-zlib-include
        --without-zlib-include=${zlib-dir}/include
        --with-zlib-lib
        --without-zlib-lib=${zlib-dir}/lib
        --enable-cross-build
        --disable-cross-build

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/nokogiri-1.10.4/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/nokogiri-1.10.4 for inspection.
Results logged to /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/nokogiri-1.10.4/gem_make.out
miriwo@miriwoPC:~$ sudo apt-get install zlib1g-dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libllvm7 linux-headers-4.18.0-17 linux-headers-4.18.0-17-generic linux-image-4.18.0-17-generic linux-modules-4.18.0-17-generic linux-modules-extra-4.18.0-17-generic
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  zlib1g-dev
0 upgraded, 1 newly installed, 0 to remove and 38 not upgraded.
Need to get 176 kB of archives.
After this operation, 457 kB of additional disk space will be used.
Get:1 http://jp.archive.ubuntu.com/ubuntu bionic/main amd64 zlib1g-dev amd64 1:1.2.11.dfsg-0ubuntu2 [176 kB]
Fetched 176 kB in 0s (453 kB/s)    
Selecting previously unselected package zlib1g-dev:amd64.
(Reading database ... 225859 files and directories currently installed.)
Preparing to unpack .../zlib1g-dev_1%3a1.2.11.dfsg-0ubuntu2_amd64.deb ...
Unpacking zlib1g-dev:amd64 (1:1.2.11.dfsg-0ubuntu2) ...
Setting up zlib1g-dev:amd64 (1:1.2.11.dfsg-0ubuntu2) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
miriwo@miriwoPC:~$ gem install rails
Building native extensions. This could take a while...
Successfully installed nokogiri-1.10.4
Successfully installed crass-1.0.5
Successfully installed loofah-2.3.1
Successfully installed rails-html-sanitizer-1.3.0
Successfully installed rails-dom-testing-2.0.3
Successfully installed builder-3.2.3
Successfully installed erubi-1.9.0
Successfully installed actionview-6.0.0
Successfully installed actionpack-6.0.0
Successfully installed activemodel-6.0.0
Successfully installed activerecord-6.0.0
Successfully installed globalid-0.4.2
Successfully installed activejob-6.0.0
Successfully installed mini_mime-1.0.2
Successfully installed mail-2.7.1
Successfully installed actionmailer-6.0.0
Building native extensions. This could take a while...
Successfully installed nio4r-2.5.2
Successfully installed websocket-extensions-0.1.4
Building native extensions. This could take a while...
Successfully installed websocket-driver-0.7.1
Successfully installed actioncable-6.0.0
Successfully installed mimemagic-0.3.3
Successfully installed marcel-0.3.3
Successfully installed activestorage-6.0.0
Successfully installed actionmailbox-6.0.0
Successfully installed actiontext-6.0.0
Successfully installed thor-0.20.3
Successfully installed method_source-0.9.2
Successfully installed railties-6.0.0
Successfully installed sprockets-4.0.0
Successfully installed sprockets-rails-3.2.1
Successfully installed rails-6.0.0
Parsing documentation for nokogiri-1.10.4
Installing ri documentation for nokogiri-1.10.4
Parsing documentation for crass-1.0.5
Installing ri documentation for crass-1.0.5
Parsing documentation for loofah-2.3.1
Installing ri documentation for loofah-2.3.1
Parsing documentation for rails-html-sanitizer-1.3.0
Installing ri documentation for rails-html-sanitizer-1.3.0
Parsing documentation for rails-dom-testing-2.0.3
Installing ri documentation for rails-dom-testing-2.0.3
Parsing documentation for builder-3.2.3
Installing ri documentation for builder-3.2.3
Parsing documentation for erubi-1.9.0
Installing ri documentation for erubi-1.9.0
Parsing documentation for actionview-6.0.0
Installing ri documentation for actionview-6.0.0
Parsing documentation for actionpack-6.0.0
Installing ri documentation for actionpack-6.0.0
Parsing documentation for activemodel-6.0.0
Installing ri documentation for activemodel-6.0.0
Parsing documentation for activerecord-6.0.0
Installing ri documentation for activerecord-6.0.0
Parsing documentation for globalid-0.4.2
Installing ri documentation for globalid-0.4.2
Parsing documentation for activejob-6.0.0
Installing ri documentation for activejob-6.0.0
Parsing documentation for mini_mime-1.0.2
Installing ri documentation for mini_mime-1.0.2
Parsing documentation for mail-2.7.1
Installing ri documentation for mail-2.7.1
Parsing documentation for actionmailer-6.0.0
Installing ri documentation for actionmailer-6.0.0
Parsing documentation for nio4r-2.5.2
Installing ri documentation for nio4r-2.5.2
Parsing documentation for websocket-extensions-0.1.4
Installing ri documentation for websocket-extensions-0.1.4
Parsing documentation for websocket-driver-0.7.1
Installing ri documentation for websocket-driver-0.7.1
Parsing documentation for actioncable-6.0.0
Installing ri documentation for actioncable-6.0.0
Parsing documentation for mimemagic-0.3.3
Installing ri documentation for mimemagic-0.3.3
Parsing documentation for marcel-0.3.3
Installing ri documentation for marcel-0.3.3
Parsing documentation for activestorage-6.0.0
Installing ri documentation for activestorage-6.0.0
Parsing documentation for actionmailbox-6.0.0
Installing ri documentation for actionmailbox-6.0.0
Parsing documentation for actiontext-6.0.0
Installing ri documentation for actiontext-6.0.0
Parsing documentation for thor-0.20.3
Installing ri documentation for thor-0.20.3
Parsing documentation for method_source-0.9.2
Installing ri documentation for method_source-0.9.2
Parsing documentation for railties-6.0.0
Installing ri documentation for railties-6.0.0
Parsing documentation for sprockets-4.0.0
Installing ri documentation for sprockets-4.0.0
Parsing documentation for sprockets-rails-3.2.1
Installing ri documentation for sprockets-rails-3.2.1
Parsing documentation for rails-6.0.0
Installing ri documentation for rails-6.0.0
Done installing documentation for nokogiri, crass, loofah, rails-html-sanitizer, rails-dom-testing, builder, erubi, actionview, actionpack, activemodel, activerecord, globalid, activejob, mini_mime, mail, actionmailer, nio4r, websocket-extensions, websocket-driver, actioncable, mimemagic, marcel, activestorage, actionmailbox, actiontext, thor, method_source, railties, sprockets, sprockets-rails, rails after 48 seconds
31 gems installed
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む