- 投稿日:2019-10-02T23:20:23+09:00
Rubyの `OpenSSL::BN` で手軽に合同算術(余りの計算)
Rubyの数値クラスは基本的に
Numeric
のサブクラスだが、そうなっていなく隠れているものがある。それがopensslライブラリ内のOpenSSL::BN
。(他にもあるかもしれないけど)OpenSSL内で利用される多倍長整数クラスです。
通常多倍長整数を利用するには
Bignum
を用いてください。暗号化に利用する計算が目的のため、通常の整数クラスには無いメソッドがいくつか用意されている。そのひとつに剰余をとりながらの演算(合同算術)が挙げられる。
合同算術メソッドの一覧
通常の演算子
+
,-
,*
,/
(divmod),**
もありInteger
と混ぜて使えるが、それに加えて#mod_xxx
というメソッドが用意されている。これらは引数に法(modulus)を指定する。
- 加算 :
#mod_add
- 減算 :
#mod_sub
- 乗算 :
#mod_mul
- 累乗(冪剰余) :
#mod_exp
- 自乗(平方剰余) :
#mod_sqr
- 逆元(モジュラー逆数) :
#mod_inverse
このうち冪剰余とモジュラー逆数は、自力で効率よく計算しようとするとアルゴリズムの知識がそれなりに必要になる。これを標準ライブラリに任せられるのは嬉しい。
なお、冪剰余についてはRuby2.5から
Integer#pow
でもできるようになった。モジュラー逆数は以前に自作してみたことがあるが、このクラスを知っていたらわざわざやらなかったかも。冪剰余とフェルマーの小定理a = 12345 # any integer n = 6700417 # prime number # OpenSSL::BN require 'openssl' a.to_bn.mod_exp(n, n).to_i #=> a % n # Integer (built-in class) a ** n % n #=> NaN (warning: in a**b, b may be too big) a.pow(n, n) #=> a % nモジュラー逆数63 * 27 % 100 == 1 # OpenSSL::BN require 'openssl' 63.to_bn.mod_inverse(100).to_i #=> 27 64.to_bn.mod_inverse(100).to_i #=> OpenSSL::BNError: no inverse # https://www.rubydoc.info/gems/numeric_inverse require 'numeric_inverse' using NumericInverse 63.inv(100) #=> 27 64.inv(100) #=> ArgumentError: modulus 100 is not coprime to 64利用例:RSA暗号の復号の計算
最近計算する機会があったので、
OpenSSL::BN
でもやってみる。主な変数は以下の通り。
- 公開鍵 (n, e) は誰でも手に入る
- n は2つの素数の積
- e は適当な数1(※満たすべき条件はある)
- 秘密鍵 (n, d) は鍵ペアの作成者しか知らない
- n は公開鍵と同じ2
- d は e と対になる数
- m と c はそれぞれ平文と暗号文(を数値化したもの)
- m から c を求めるのが暗号化で、公開鍵によって誰でも可能
- c から m を求めるのが復号で、秘密鍵によって鍵ペアの作成者のみ可能
- 秘密鍵の d を知らずに復号できたら暗号解読成功
Wikipedia英語版にある例で復号を試す。公開鍵しか知らない状態でも、 n を素因数分解した2つの素数がわかれば、秘密鍵を求められる。
require 'openssl' n, e = 3233, 17 # public key (n, e) c = 2790 # ciphertext # discover that 3233 == 61 * 53 # --> get a private key (n, d) l = [61 - 1, 53 - 1].inject(:lcm) d = e.to_bn.mod_inverse(l).to_i #=> 413 # decrypt m = c.to_bn.mod_exp(d, n).to_i #=> 65 (plaintext) # encrypt again c = m.to_bn.mod_exp(e, n).to_i #=> 2790 (ciphertext)
- 投稿日:2019-10-02T22:49:23+09:00
【Rspec】attributes_forってなんだ...
はじめに
ポートフォリオの機能を一通り実装し終えたので、Everyday Railsで勉強をしながらRspecでテストを書き始めました。
モデルスペックを書き終え、コントローラスペックを書いている際に「attributes_for」に出会い、ちょっと詰まったので記事にします。
attributes_forとは
Everyday Railsによると、「プロジェクトファクトリからテスト用の属性値をハッシュとして作成します。」、だそうです。
最初の感想としては、「なんのために???buildでよくない???」でした。
まずは見てみよう
buildとattrubutes_forの違いを以下に示します。
まずはFactoryの中身です。
users.rbFactoryBot.define do factory :user do name "test" sequence(:email) { |n| "test#{n}@test.com"} password "password" end endposts.rbFactoryBot.define do factory :post do content 'test content' association :user end endこれらを用いたbuildとattributes_forで取得するデータの違いが以下の通りです。
build> FactoryBot.build(:post) => #<Post id: nil, content: "test content", user_id: 8, created_at: nil, updated_at: nil>attributes_for> FactoryBot.attributes_for(:post) => {:name=>"test", :email=>"test2@test.com", :password=>"password"}buildはモデルオブジェクト、attributes_forはハッシュとなっていますね。(間違えてたら教えてください)
つまり
パラメータとして値を渡す場合、ハッシュを使って渡すことができます。複数のパラメータを送信する場合に、個々にパラメータ名を付けるのではなく、キーと値を組み合わせたハッシュとして渡せます。
これは実際に見てもらったほうがわかりやすいと思います。
posts_controller_spec.rb#省略 describe "#create" do context "ログインユーザーとして" do before do @user = FactoryBot.create(:user) end it "投稿ができる" do post_params = FactoryBot.attributes_for(:post) sign_in @user expect{ post :create, params: { post: post_params} }.to change(@user.posts, :count).by(1) end end endこのプログラムの、post :create, params: { post: post_params}に注目してください。
これは、post :create, params: { post: {:name=>"test", :email=>"test2@test.com", :password=>"password"} }このプログラムと同義となります。
つまり、POSTメソッドで渡すparamsにpostキーを渡し、そのpostキーのValueをattributes_forの返り値であるハッシュを渡すことで、このように簡潔に書くことができます。(説明下手ですみません...)上記より、buildではなくattributes_forを使用している意味がわかりました。
最後に
私はまだ業界未経験で、なおかつRspecを書き始めて2日目です。
間違えている部分などありましたら、教えてもらえると非常に助かります。以上です。
- 投稿日:2019-10-02T22:16:40+09:00
rbenvでのruby2.6.1インストール時「Agreeing to the Xcode/iOS license requires admin privileges」で失敗
ruby 2.6.1をrbenvを用いてインストールしようとしたときになぜか落ちたので共有。
落ちた箇所
$ rbenv install 2.6.1 Wed Oct 2 15:02:22 2019 Downloading openssl-1.1.0j.tar.gz... -> https://dqw8nmjcqpjn7.cloudfront.net/31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246 Installing openssl-1.1.0j... BUILD FAILED (OS X 10.14.6 using ruby-build 20190423) Inspect or clean up the working tree at /var/folders/y4/jzf9wps144x1w4hp2kwp359xrk7xs7/T/ruby-build.20191002150224.4456 Results logged to /var/folders/y4/jzf9wps144x1w4hp2kwp359xrk7xs7/T/ruby-build.20191002150224.4456.log SIXTY_FOUR_BIT_LONG mode Configured for darwin64-x86_64-cc. Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.こいつが怪しい。
Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.
Xcodeのライセンスがどーのと言われているっぽい...
素直にコマンドを実行
エラー文章通りコマンドを実行する。
$ sudo xcodebuild -license You have not agreed to the Xcode license agreements. You must agree to both license agreements below in order to use Xcode.すると、ずらーーーーーーーーっとライセンスの情報が出ます(文章を共有するのはやめときます)
q
で抜けると、「agree」, 「print」, 「cancel」の3つから操作を求められるので、ターミナル上で「agree」と入力しEnterを押す。By typing 'agree' you are agreeing to the terms of the software license agreements. Type 'print' to print them or anything else to cancel, [agree, print, cancel] agree # agreeを入力してEnter You can view the license agreements in Xcode's About Box, or at /Applications/Xcode.app/Contents/Resources/English.lproj/License.rtfすると、インストールできる。
rbenv install 2.6.1 28.2s Wed Oct 2 15:03:58 2019 ruby-build: use openssl from homebrew Downloading ruby-2.6.1.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.1.tar.bz2 Installing ruby-2.6.1... ruby-build: use readline from homebrew Installed ruby-2.6.1 to /Users/xxxxxx/.rbenv/versions/2.6.1なぜライセンス同意をいまさら求められたのかはよくわかりませんが、インストールできたのでOK。
- 投稿日:2019-10-02T21:30:49+09:00
【Rails】ページ内で読み込みたいCSSを�制御する
ソースコードを見ると
/app/assets/stylesheets/
以下にあるファイルを読み込む記述が自動で書き出されている。
その記述に関してあれこれ変更したかったのでやってみました。一応環境情報を載せておきます。
ruby:2.6.4
rails:5.2.3
目的
1.ページ内に自動記述されるCSSの読み込み順番を変更したい。
2.SASS使用のためのimportさせるファイルは読み込ませたくない。方法
自動記述の制御はある程度
/app/assets/stylesheets/application.scss
内で調整ができる。application.scss(初期状態)/* * This is a manifest file that'll be compiled into application.css, which will include all the files | * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's | * vendor/assets/stylesheets directory can be referenced here using a relative path. | * * You're free to add application-wide styles to this file and they'll appear at the bottom of the | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS | * files in this directory. Styles in this file should be added after the last require_* statement. | * It is generally better to create a new file per style scope. | * *= require_tree . *= require_self */
1.ページ内に自動記述されるCSSの読み込み順番を変更したい。
下部にある
*= require_tree .
から*= require_self
までを変更する。
アセットパイプラインの仕組みにより、ここで読み込みに関して調整可能。
この仕組みはディレクティブと呼ばれている。
(※デフォルトだとアルファベット順?)今回は最下部に記述される
application.css
を最上部にしたいので以下のように記述しました。application.scss(変更後)*= require_self *= require_tree .変更点は、単純に記述の順番を入れ替えただけ。
*= require_tree .
はインクルードさせる記述。
(.
とあるので/app/assets/stylesheets/
を指定していることになる?)
*= require_self
は正直よくわからなかった・・・。勉強します。例えば
hoge01.css
、hoge02.css
...の順で絶対並べたい!という場合は、application.scss*= require_self *= require hoge01.css *= require hoge02.css *= require_tree .のように書いてあげればOK。
ただし、今の状態だと
/app/assets/stylesheets/
以下全てのファイルが自動記述されてしまうので、次で調整する。2.SASS使用のためのimportさせるファイルは読み込ませたくない。
自分はSASSで使用する変数ファイルなどを
/app/assets/stylesheets/partial/
以下に格納しました。
ひとまずサブディレクトリは読み込まれないようにします。application.scss(変更後)*= require_self *= require_directory .
*= require_tree .
→*= require_directory .
に変更するだけ。
*= require_directory .
は/app/assets/stylesheets/pretial/
直下にあるファイルだけ読み込むよ、というもの。自動でやってくれるのはとても便利ですので、なおさら制御方法は知っておかなきゃいけないなと痛感。
まだまだRails開発を始めたばかりなので、今後深掘りしていこうと思います。参考サイト
RailsでCSSの読み込む順番を制御する方法 - Qiita
Rails 使用するCSSを指定する | | KeruuWeb
Railsのマニフェストファイルを使ったJsとStylesheetの呼び出し - Qiita
- 投稿日:2019-10-02T20:47:47+09:00
[質問です。]rubyのapiの叩き方について
rubyでapiを叩きたい
現在プログラミング歴1ヶ月でlinebotを作成しながら勉強しています。
ぐるなびAPIをlinebotに使用したい
ぐるなびAPIをlinebotに使用する所でつまづいており、皆様にご質問があります。
下記エラーが解決出来ません
NoMethodError (undefined method `sample' for nil:NilClass):該当コードは
linebot_controller.rbevents.each { |event| if event.message['text'] != nil place = event.message['text'] #ここでLINEで送った文章を取得 result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008&category_s=RSFST08009&#{place}` else latitude = event.message['latitude'] longitude = event.message['longitude'] result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008category_s=RSFST08009&latitude=#{latitude}longitude=#{longitude}`#ここでぐるなびAPIを叩く end hash_result = JSON.parse result #レスポンスが文字列なのでhashにパースする shops = hash_result["rest"] #ここでお店情報が入った配列となる shop = shops.sample #任意のものを一個選ぶhash_result = JSON.parse result 部分まではしっかり値が入っているのですが、
shops = hash_result["rest"] ←この部分がnilで返ってきてしまいエラーを吐き出してしまいます。
文法のミス等自分なりにapiを叩く記述を参考にしながら行なったのですが解決出来ません。
皆様のお力をお貸しいただけると幸いです。以下参考記事
https://qiita.com/NoharaMasato/items/6fb1ac277c965905e019
- 投稿日:2019-10-02T20:47:47+09:00
(質問です)rubyのapiの叩き方について
rubyでapiを叩きたい
現在プログラミング歴1ヶ月でlinebotを作成しながら勉強しています。
ぐるなびAPIをlinebotに使用したい
ぐるなびAPIをlinebotに使用する所でつまづいており、皆様にご質問があります。
下記エラーが解決出来ません
NoMethodError (undefined method `sample' for nil:NilClass):該当コードは
linebot_controller.rbevents.each { |event| if event.message['text'] != nil place = event.message['text'] #ここでLINEで送った文章を取得 result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008&category_s=RSFST08009&#{place}` else latitude = event.message['latitude'] longitude = event.message['longitude'] result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008category_s=RSFST08009&latitude=#{latitude}longitude=#{longitude}`#ここでぐるなびAPIを叩く end hash_result = JSON.parse result #レスポンスが文字列なのでhashにパースする shops = hash_result["rest"] #ここでお店情報が入った配列となる shop = shops.sample #任意のものを一個選ぶhash_result = JSON.parse result 部分まではしっかり値が入っているのですが、
shops = hash_result["rest"] ←この部分がnilで返ってきてしまいエラーを吐き出してしまいます。
文法のミス等自分なりにapiを叩く記述を参考にしながら行なったのですが解決出来ません。
皆様のお力をお貸しいただけると幸いです。以下参考記事
https://qiita.com/NoharaMasato/items/6fb1ac277c965905e019
- 投稿日:2019-10-02T20:40:44+09:00
【小学生でもわかる】Ruby 戻り値 return
【Ruby】戻り値 returnとは
今流行りのキャッシュレス決済になぞらえてわかりやすく解説
sample.rbdef discount(price) return price * 0.95 end cashless = discount(5000) puts "キャッシュレス決済で5%還元セール実施中!" puts "#{price}円の買い物が実質#{cashless}円に!"解説
「もともと5000円のものがキャッシュレス決済を利用すると5%オフになって実質4750円になる」という文
「このひみつ道具を使うとpriceが自動的に5%オフになるんだよ〜」みたいな状況
(discountという名前のメソッド)
(どらえもんのガリバートンネル的な)pirce:元の値段
discount:自動で5%オフしてくれるシステムみたいなもの(メソッド)
cashless:計算結果まとめ
cashless = priceにdiscountメソッドを適用した結果
【番外編】複数の戻り値をネットショッピングを例に解説
「〇〇円以上のお買い物だと送料無料」みたいなことよくありますよね
sample.rbdef online_shopping(price) if price >= 2000 return price end return price + 220 end puts "合計金額は1500円です" puts "金額は、送料込みで#{online_shopping(1500)}円です" puts "-----------" puts "商品の合計金額は10000円です" puts "金額は、送料込みで#{price_with_shipping(10000)}円です"結果
合計金額は1500円です"
お支払い金額は、送料込みで1720円です"あるいは
合計金額は10000円です"
お支払い金額は、送料込みで10000円です"と表示される
解説
これは2000円以上のお買い物で送料が無料になる文。
2000円以上の時はそのままpriceの値が表示されるようにする、
それ以下の時はpriceに送料である220円を足した値が表示されるようにする
- 投稿日:2019-10-02T20:34:35+09:00
presence メソッド
- 投稿日:2019-10-02T20:27:12+09:00
binding.pryの使い方
デバッグツールのbinding.pryの基本的な使い方の備忘録
- gemfileに
binding.pry
を記述- ターミナルでbundle insatall を実施する
- 動作を止めたいところ(変数の中身を確認したいところ)に挿入する。
user_contorller.rbdef login @user = User.find_by( email:params[:email], password:params[:password] ) binding.pry if @user flash[:notice] = "ログインしました" redirect_to action: :index else @error_message = "メールアドレスまたはパスワードが間違っています" @email = params[:email] @password = params[:password] render action: :login_form end endアクションに該当する動作を実施するとターミナルに以下のように表示される。
40: def login 41: @user = User.find_by( 42: email:params[:email], 43: password:params[:password] 44: ) 45: binding.pry => 46: if @user 47: flash[:notice] = "ログインしました" 48: redirect_to action: :index 49: else 50: @error_message = "メールアドレスまたはパスワードが間違っています" 51: @email = params[:email] 52: @password = params[:password] 53: render action: :login_form 54: end 55: endあとはterminalで確認したい中身の変数をたたけば確認できる!
[1] pry(#<UsersController>)> @user => nil
- 投稿日:2019-10-02T19:47:43+09:00
【小学生でもわかる】Ruby メソッド
【Ruby】でメソッドを使用する
sample.rbdef introduction(hobby) puts "はじめましてよろしくお願いします" puts "趣味は#{hobby}です" end「自己紹介の場面が来たらこうやって言おう!」というフォーマット
「でも趣味は場面に応じて言い換えよう」と考えているみたいですねsample.rb# 当たり障りないこと言っておこう...って時 introduction("映画鑑賞") # 女の子ウケが良さそうなこと言おう...って時 introduction ("タピオカ旅")結果
はじめましてよろしくお願いします
趣味は映画鑑賞ですあるいは
はじめましてよろしくお願いします
趣味はタピオカ旅ですなどと言い換えることができました。
- 投稿日:2019-10-02T19:47:43+09:00
【小学生でもわかる】Ruby メソッド 引数
【Ruby】でメソッドを使用する
sample.rbdef introduction(hobby) puts "はじめましてよろしくお願いします" puts "趣味は#{hobby}です" end「自己紹介の場面が来たらこうやって言おう!」というテンプレート
「でも趣味は場面に応じて言い換えよう」と考えているみたいですねsample.rb# 当たり障りないこと言っておこう...って時 introduction("映画鑑賞") # 女の子ウケが良さそうなこと言おう...って時 introduction ("タピオカ旅")結果
はじめましてよろしくお願いします
趣味は映画鑑賞ですあるいは
はじめましてよろしくお願いします
趣味はタピオカ旅ですなどと言い換えることができました。
まとめ
引数とは
「ある程度用意したテンプレートに場合に応じていろんなもの入れるぜ!」
というもの
- 投稿日:2019-10-02T19:45:55+09:00
クラス、インスタンスのまとめ
今勉強しているrubyのクラス、インスタンスについてまとめていきます。間違いなどございましたら教えてください!
クラス
メソッドなどのいろんな処理を入れておく箱のようなものです。
このクラスを定義して、rubyに新しい定義を追加することができます。
定義方法はwork.rbclass Name #処理 endこのような形です。クラス名は大文字で始めることに注意します。
インスタンス
まずクラスに処理を書いていきます。
work.rbclass Name def initialize @name = "ヤマモト" end def a @name + "タロウ" end endinitializeメソッドとはインスタンスを作った際に自動で呼び出されるメソッドです。
aで定義している部分をインスタンスメソッドと呼びます。
@から始まっているのはインスタンス変数と呼び、ローカル変数とは違ってクラス内の全メソッドで共通して使うことができます。
上記の処理を実際に行うためにはインスタンスを生成して、クラスを呼び出す必要があります。
インスタンスの生成にはnewメソッドを用います。work.rbclass Name def initialize @name = "ヤマモト" end def a @name + "タロウ" end end pon = Name.new puts pon.a # => ヤマモトタロウ上記のようにnewを使ってインスタンスを生成した後、変数ponにインスタンスを結んでます。
そして最後に出力される処理を書きました。以上がクラスとインスタンスについてまとめたものです。
- 投稿日:2019-10-02T19:27:53+09:00
【Ruby】Slack APIを使用してメッセージを送信する
前提
この記事は以下の前提で書きます。
まだの方はこちらの記事を参考にして準備を進めてください。
- Slack APIで使用するトークンを取得済みであること
- APIにメッセージ送信の権限を与えていること
準備
slack-ruby-client
をインストールします。
下記コマンドを実行するか、Gemfile
に追記します。$ gem install slack-ruby-clientor
Gemfilegem 'slack-ruby-client'ソースコード
slack.rbrequire 'slack-ruby-client' Slack.configure do |config| # APIトークンを設定 config.token = 'xoxp-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' end # APIクライアントを生成 client = Slack::Web::Client.new # #チャンネル名 of @ユーザー名 channel = '#slack-test' # メッセージ text = 'Hello World' response = client.chat_postMessage(channel: channel, text: text, as_user: false) pp response実行してみる
$ ruby slack.rb {"ok"=>true, ...参考
- 投稿日:2019-10-02T19:22:48+09:00
[初心者]Rails6にbootstrap4を導入する
Ruby on railsを学び始めて約2ヶ月、
初めてbootstrapを導入したので、記事を作ってみました。
環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.14.6 BuildVersion: 18G95 $ ruby -v ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin18] $ rails -v Rails 6.0.0
目次
bootstrap
のgem
を追加applicationファイル
を編集index.html.erb
を編集bootstrap
が導入されているかを確認
1.bootstrap gemを追加
Gemfileに以下を追加
Gemfile~ gem 'bootstrap', '~> 4.1.1' gem 'jquery-rails' ~
terminal
でbundle install
を実行
(ローカルでgemを管理している場合は、bundle install --path=vendor/bundle
で実行)これで、プロジェクト内にbootstrapのgemが追加されました。
2.applicationファイルを編集
2.1 application.cssの編集
app>assets>stylesheets>application.cssをエディタで開き、
@import "bootstrap";
を追加application.css~ @import "bootstrap"; ~次に拡張子を
.css
から.scss
へ変更
application.css → application.scss2.2 application.jsの編集
app>assets>javascript>application.jsをエディタで開き、
//= require bootstrap
を追加
(フォルダ、ファイルがなければ作成)
bootstrapはjqueryとpopperに依存しているらしいので導入application.js//= require jquery3 //= require popper //= require bootstrap-sprockets3.index.html.erb を編集
適当なcontrollerに以下のコードを追加
app>assets>views>コントローラ名>index.html.erb
このコードはbootstrapのサイトにあるテストコードです。index.html.erb<a class="btn btn-primary" href="#" role="button">Link</a> <button class="btn btn-primary" type="submit">Button</button> <input class="btn btn-primary" type="button" value="Input"> <input class="btn btn-primary" type="submit" value="Submit"> <input class="btn btn-primary" type="reset" value="Reset">4.動作確認
下準備は整いました。
bundle exec rails s
でローカルにサーバーを立ち上げます。
ブラウザにlocalhost:3000/コントローラ名/index
を入力し、画面を確認してください。
以下の表示になっていれば完了です。
- 投稿日:2019-10-02T18:51:50+09:00
ISUCON9予選感想戦
はじめに
本記事では、ISUCON9の予選問題をローカル環境で実行しながら振り返りを行います。言語はrubyで行います。
環境構築
環境構築には以下のリポジトリのVagrantfileを使用します。
https://github.com/matsuu/vagrant-isucon本番との違いはREADME.mdにも記載のある通り、スペックと台数です。
初期実装のスコア
実装をrubyに切り替えてベンチマークを実行します。
- 実装の切り替え
$ sudo systemctl stop isucari.golang.service $ sudo systemctl disable isucari.golang.service $ sudo systemctl start isucari.ruby.service $ sudo systemctl enable isucari.ruby.service
- ベンチマークの実行
ベンチマークは本番と同様にNginxを通して実行したいので、target_urlを指定して実行します。
$ ./bin/benchmarker -target-url https://127.0.0.1実行結果は以下の通りです。
{"pass":true,"score":2010,"campaign":0,"language":"ruby","messages":[]}アクセスログを解析する
alp v0.4.0を使用してアクセスログの解析をします。
https://github.com/tkuchiki/alpv1.0.0もありますが、事前準備の段階でv1.0.0が上手く動かなかったため、v0.4.0を使用しました。
$ sudo wget https://github.com/tkuchiki/alp/releases/download/v0.4.0/alp_linux_amd64.zip $ sudo unzip alp_linux_amd64.zip $ sudo mv alp /usr/bin/Nginxのログをalpで解析できる形式にします。
nginx.confを修正したらNginxを再起動する必要があります。nginx.conflog_format ltsv "time:$time_local" "\thost:$remote_addr" "\tforwardedfor:$http_x_forwarded_for" "\treq:$request" "\tstatus:$status" "\tmethod:$request_method" "\turi:$request_uri" "\tsize:$body_bytes_sent" "\treferer:$http_referer" "\tua:$http_user_agent" "\treqtime:$request_time" "\tcache:$upstream_http_x_cache" "\truntime:$upstream_http_x_runtime" "\tapptime:$upstream_response_time" "\tvhost:$host"; access_log /var/log/nginx/access.log ltsv;この状態で改めてベンチマークを実行し、アクセスログを解析します。
集計の正規表現はalpの結果を見ながら適当に足して行きました。$ sudo cat /var/log/nginx/access.log | alp --aggregates="/users/\d+.json","/items/\d+.json","/new_items/\d+.json","/upload/.+.jpg","/transactions/\d+.png"結果は以下のように表示されます。
大きな時間を取っているGET /users/transactions.json
やGET /new_items/\d+.json
から対応していく方針になります。+-------+--------+-------------------------------------+-----+------+-----+-----+-----+-------+-------+---------+-------+-------+-------+-------+--------+------------+------------+--------------+------------+ | COUNT | METHOD | URI | 1XX | 2XX | 3XX | 4XX | 5XX | MIN | MAX | SUM | AVG | P1 | P50 | P99 | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) | +-------+--------+-------------------------------------+-----+------+-----+-----+-----+-------+-------+---------+-------+-------+-------+-------+--------+------------+------------+--------------+------------+ | 1 | GET | /static/js/runtime~main.a8a9905a.js | 0 | 1 | 0 | 0 | 0 | 0.008 | 0.008 | 0.008 | 0.008 | 0.008 | 0.008 | 0.008 | 0.000 | 1502.000 | 1502.000 | 1502.000 | 1502.000 | | 34 | GET | /transactions/\d+.png | 0 | 22 | 0 | 12 | 0 | 0.004 | 0.012 | 0.124 | 0.004 | 0.000 | 0.004 | 0.000 | 0.004 | 32.000 | 626.000 | 13945.000 | 410.147 | | 1 | GET | /reports.json | 0 | 1 | 0 | 0 | 0 | 0.012 | 0.012 | 0.012 | 0.012 | 0.012 | 0.012 | 0.012 | 0.000 | 94019.000 | 94019.000 | 94019.000 | 94019.000 | | 1 | GET | /static/js/2.ff6e1067.chunk.js | 0 | 1 | 0 | 0 | 0 | 0.032 | 0.032 | 0.032 | 0.032 | 0.032 | 0.032 | 0.032 | 0.000 | 508459.000 | 508459.000 | 508459.000 | 508459.000 | | 9 | POST | /items/edit | 0 | 3 | 0 | 6 | 0 | 0.004 | 0.052 | 0.092 | 0.010 | 0.004 | 0.008 | 0.012 | 0.015 | 57.000 | 92.000 | 615.000 | 68.333 | | 1 | GET | /static/css/main.19393e92.chunk.css | 0 | 1 | 0 | 0 | 0 | 0.052 | 0.052 | 0.052 | 0.052 | 0.052 | 0.052 | 0.052 | 0.000 | 994.000 | 994.000 | 994.000 | 994.000 | | 57 | GET | /upload/.+.jpg | 0 | 57 | 0 | 0 | 0 | 0.004 | 0.128 | 1.644 | 0.029 | 0.008 | 0.024 | 0.004 | 0.025 | 51229.000 | 130127.000 | 4362729.000 | 76539.105 | | 13 | POST | /bump | 0 | 13 | 0 | 0 | 0 | 0.004 | 0.352 | 0.756 | 0.058 | 0.076 | 0.068 | 0.008 | 0.092 | 90.000 | 91.000 | 1171.000 | 90.077 | | 1 | GET | /static/js/main.babc3d4d.chunk.js | 0 | 1 | 0 | 0 | 0 | 0.452 | 0.452 | 0.452 | 0.452 | 0.452 | 0.452 | 0.452 | 0.000 | 90365.000 | 90365.000 | 90365.000 | 90365.000 | | 53 | GET | /settings | 0 | 53 | 0 | 0 | 0 | 0.012 | 0.488 | 6.173 | 0.116 | 0.048 | 0.092 | 0.000 | 0.125 | 3086.000 | 3100.000 | 163919.000 | 3092.811 | | 2207 | GET | /items/\d+.json | 0 | 2206 | 0 | 1 | 0 | 0.005 | 0.517 | 16.024 | 0.007 | 0.008 | 0.004 | 0.012 | 0.019 | 0.000 | 4041.000 | 4840278.000 | 2193.148 | | 61 | POST | /login | 0 | 53 | 0 | 8 | 0 | 0.060 | 0.781 | 18.730 | 0.307 | 0.124 | 0.389 | 0.060 | 0.183 | 72.000 | 266.000 | 14293.000 | 234.311 | | 52 | POST | /sell | 0 | 34 | 0 | 18 | 0 | 0.004 | 0.820 | 5.281 | 0.102 | 0.080 | 0.000 | 0.008 | 0.204 | 12.000 | 105.000 | 1836.000 | 35.308 | | 40 | POST | /ship_done | 0 | 22 | 0 | 18 | 0 | 0.816 | 0.824 | 19.747 | 0.494 | 0.020 | 0.000 | 0.000 | 0.392 | 28.000 | 82.000 | 1602.000 | 40.050 | | 21 | POST | /complete | 0 | 20 | 0 | 1 | 0 | 0.004 | 0.876 | 14.621 | 0.696 | 0.008 | 0.828 | 0.832 | 0.287 | 0.000 | 33.000 | 660.000 | 31.429 | | 38 | POST | /ship | 0 | 26 | 0 | 12 | 0 | 0.808 | 0.937 | 19.301 | 0.508 | 0.020 | 0.820 | 0.828 | 0.398 | 28.000 | 60.000 | 1944.000 | 51.158 | | 267 | GET | /users/\d+.json | 0 | 267 | 0 | 0 | 0 | 0.008 | 1.325 | 53.977 | 0.202 | 0.168 | 0.072 | 0.120 | 0.199 | 97.000 | 23995.000 | 3711121.000 | 13899.330 | | 51 | POST | /buy | 0 | 27 | 0 | 24 | 0 | 0.000 | 2.029 | 48.036 | 0.942 | 0.004 | 1.613 | 1.640 | 0.809 | 28.000 | 48.000 | 1809.000 | 35.471 | | 130 | GET | /new_items.json | 0 | 130 | 0 | 0 | 0 | 0.048 | 2.045 | 51.348 | 0.395 | 0.508 | 0.097 | 0.188 | 0.320 | 23011.000 | 23940.000 | 3043699.000 | 23413.069 | | 700 | GET | /new_items/\d+.json | 0 | 698 | 0 | 2 | 0 | 0.028 | 2.061 | 167.766 | 0.240 | 0.088 | 0.088 | 0.148 | 0.217 | 0.000 | 24044.000 | 16387888.000 | 23411.269 | | 1 | POST | /initialize | 0 | 1 | 0 | 0 | 0 | 7.156 | 7.156 | 7.156 | 7.156 | 7.156 | 7.156 | 7.156 | 0.000 | 32.000 | 32.000 | 32.000 | 32.000 | | 160 | GET | /users/transactions.json | 0 | 151 | 0 | 9 | 0 | 0.028 | 7.467 | 450.698 | 2.817 | 0.384 | 2.613 | 3.492 | 1.551 | 0.000 | 30441.000 | 3087209.000 | 19295.056 | +-------+--------+-------------------------------------+-----+------+-----+-----+-----+-------+-------+---------+-------+-------+-------+-------+--------+------------+------------+--------------+------------+categoriesのオンメモリ化
GET /users/transactions.json
やGET /new_items/\d+.json
の実装を確認すると、get_user_simple_by_id()
とget_category_by_id()
が非常に気軽に呼ばれていることに気がつきます。
このうち、get_category_by_id()
についてはcategoriesテーブルの更新が無いため、メモリに乗せることができます。def get_category_by_id(category_id) category = categories.find{|item| item[:id] == category_id} return if category.nil? parent_category_name = if category[:parent_id] != 0 parent_category = get_category_by_id(category[:parent_id]) return if parent_category.nil? parent_category['category_name'] end { 'id' => category[:id], 'parent_id' => category[:parent_id], 'category_name' => category[:category_name], 'parent_category_name' => parent_category_name } end def categories [ {:id => 1, :parent_id => 0, :category_name => "ソファー"}, {:id => 2, :parent_id => 1, :category_name => "一人掛けソファー"}, {:id => 3, :parent_id => 1, :category_name => "二人掛けソファー"}, {:id => 4, :parent_id => 1, :category_name => "コーナーソファー"}, {:id => 5, :parent_id => 1, :category_name => "二段ソファー"}, {:id => 6, :parent_id => 1, :category_name => "ソファーベッド"}, {:id => 10, :parent_id => 0, :category_name => "家庭用チェア"}, {:id => 11, :parent_id => 10, :category_name => "スツール"}, {:id => 12, :parent_id => 10, :category_name => "クッションスツール"}, {:id => 13, :parent_id => 10, :category_name => "ダイニングチェア"}, {:id => 14, :parent_id => 10, :category_name => "リビングチェア"}, {:id => 15, :parent_id => 10, :category_name => "カウンターチェア"}, {:id => 20, :parent_id => 0, :category_name => "キッズチェア"}, {:id => 21, :parent_id => 20, :category_name => "学習チェア"}, {:id => 22, :parent_id => 20, :category_name => "ベビーソファ"}, {:id => 23, :parent_id => 20, :category_name => "キッズハイチェア"}, {:id => 24, :parent_id => 20, :category_name => "テーブルチェア"}, {:id => 30, :parent_id => 0, :category_name => "オフィスチェア"}, {:id => 31, :parent_id => 30, :category_name => "デスクチェア"}, {:id => 32, :parent_id => 30, :category_name => "ビジネスチェア"}, {:id => 33, :parent_id => 30, :category_name => "回転チェア"}, {:id => 34, :parent_id => 30, :category_name => "リクライニングチェア"}, {:id => 35, :parent_id => 30, :category_name => "投擲用椅子"}, {:id => 40, :parent_id => 0, :category_name => "折りたたみ椅子"}, {:id => 41, :parent_id => 40, :category_name => "パイプ椅子"}, {:id => 42, :parent_id => 40, :category_name => "木製折りたたみ椅子"}, {:id => 43, :parent_id => 40, :category_name => "キッチンチェア"}, {:id => 44, :parent_id => 40, :category_name => "アウトドアチェア"}, {:id => 45, :parent_id => 40, :category_name => "作業椅子"}, {:id => 50, :parent_id => 0, :category_name => "ベンチ"}, {:id => 51, :parent_id => 50, :category_name => "一人掛けベンチ"}, {:id => 52, :parent_id => 50, :category_name => "二人掛けベンチ"}, {:id => 53, :parent_id => 50, :category_name => "アウトドア用ベンチ"}, {:id => 54, :parent_id => 50, :category_name => "収納付きベンチ"}, {:id => 55, :parent_id => 50, :category_name => "背もたれ付きベンチ"}, {:id => 56, :parent_id => 50, :category_name => "ベンチマーク"}, {:id => 60, :parent_id => 0, :category_name => "座椅子"}, {:id => 61, :parent_id => 60, :category_name => "和風座椅子"}, {:id => 62, :parent_id => 60, :category_name => "高座椅子"}, {:id => 63, :parent_id => 60, :category_name => "ゲーミング座椅子"}, {:id => 64, :parent_id => 60, :category_name => "ロッキングチェア"}, {:id => 65, :parent_id => 60, :category_name => "座布団"}, {:id => 66, :parent_id => 60, :category_name => "空気椅子"} ] endget_user_simple_by_idを削除
get_user_simple_by_id()
もget_category_by_id()
と同様に非常に多く呼ばれています。
こちらはオンメモリ化は難しいので、JOINして取得するようにします。
以下に、一例としてgetNewItems
のクエリを掲載します。SELECT t1.* ,t2.`account_name` ,t2.`num_sell_items` FROM `items` AS t1 INNER JOIN `users` AS t2 ON t1.`seller_id` = t2.`id` WHERE t1.`status` IN (?, ?) ORDER BY t1.`created_at` DESC, t1.`id` DESC LIMIT #{ITEMS_PER_PAGE + 1}getTransactionsのAPI呼び出し
ここからは当日できなかった修正です。
api_client.shipment_status
はtransaction_evidenceのstatusがdoneの時には呼び出す必要が無いそうです。
修正後のスコアは以下の通りです。{"pass":true,"score":3740,"campaign":0,"language":"ruby","messages":[]}この時点でのalpの結果は以下のようになります。
+-------+--------+-------------------------------------+-----+------+-----+-----+-----+-------+-------+---------+-------+-------+-------+-------+--------+------------+------------+--------------+------------+ | COUNT | METHOD | URI | 1XX | 2XX | 3XX | 4XX | 5XX | MIN | MAX | SUM | AVG | P1 | P50 | P99 | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) | +-------+--------+-------------------------------------+-----+------+-----+-----+-----+-------+-------+---------+-------+-------+-------+-------+--------+------------+------------+--------------+------------+ | 1 | GET | /static/js/2.ff6e1067.chunk.js | 0 | 1 | 0 | 0 | 0 | 0.016 | 0.016 | 0.016 | 0.016 | 0.016 | 0.016 | 0.016 | 0.000 | 508459.000 | 508459.000 | 508459.000 | 508459.000 | | 1 | GET | /static/js/runtime~main.a8a9905a.js | 0 | 1 | 0 | 0 | 0 | 0.024 | 0.024 | 0.024 | 0.024 | 0.024 | 0.024 | 0.024 | 0.000 | 1502.000 | 1502.000 | 1502.000 | 1502.000 | | 1 | GET | /reports.json | 0 | 1 | 0 | 0 | 0 | 0.032 | 0.032 | 0.032 | 0.032 | 0.032 | 0.032 | 0.032 | 0.000 | 143390.000 | 143390.000 | 143390.000 | 143390.000 | | 50 | GET | /transactions/\d+.png | 0 | 40 | 0 | 10 | 0 | 0.008 | 0.080 | 0.544 | 0.011 | 0.008 | 0.012 | 0.012 | 0.015 | 32.000 | 623.000 | 24890.000 | 497.800 | | 11 | POST | /items/edit | 0 | 6 | 0 | 5 | 0 | 0.004 | 0.116 | 0.304 | 0.028 | 0.028 | 0.000 | 0.048 | 0.033 | 57.000 | 92.000 | 835.000 | 75.909 | | 56 | GET | /upload/.+.jpg | 0 | 56 | 0 | 0 | 0 | 0.004 | 0.180 | 2.994 | 0.053 | 0.084 | 0.068 | 0.008 | 0.043 | 51574.000 | 146187.000 | 4706042.000 | 84036.464 | | 1 | GET | /static/css/main.19393e92.chunk.css | 0 | 1 | 0 | 0 | 0 | 0.192 | 0.192 | 0.192 | 0.192 | 0.192 | 0.192 | 0.192 | 0.000 | 994.000 | 994.000 | 994.000 | 994.000 | | 1 | GET | /static/js/main.babc3d4d.chunk.js | 0 | 1 | 0 | 0 | 0 | 0.520 | 0.520 | 0.520 | 0.520 | 0.520 | 0.520 | 0.520 | 0.000 | 90365.000 | 90365.000 | 90365.000 | 90365.000 | | 13 | POST | /bump | 0 | 13 | 0 | 0 | 0 | 0.004 | 0.529 | 1.821 | 0.140 | 0.156 | 0.028 | 0.080 | 0.164 | 89.000 | 91.000 | 1168.000 | 89.846 | | 52 | GET | /settings | 0 | 52 | 0 | 0 | 0 | 0.008 | 0.568 | 7.472 | 0.144 | 0.044 | 0.320 | 0.040 | 0.153 | 3086.000 | 3103.000 | 160855.000 | 3093.365 | | 60 | POST | /login | 0 | 52 | 0 | 8 | 0 | 0.100 | 0.740 | 22.886 | 0.381 | 0.576 | 0.452 | 0.184 | 0.190 | 72.000 | 269.000 | 14063.000 | 234.383 | | 55 | POST | /ship_done | 0 | 39 | 0 | 16 | 0 | 0.004 | 0.896 | 33.709 | 0.613 | 0.016 | 0.004 | 0.853 | 0.360 | 0.000 | 82.000 | 2017.000 | 36.673 | | 65 | POST | /sell | 0 | 50 | 0 | 15 | 0 | 0.004 | 0.936 | 8.002 | 0.123 | 0.068 | 0.016 | 0.080 | 0.208 | 12.000 | 105.000 | 1790.000 | 27.538 | | 390 | GET | /users/\d+.json | 0 | 386 | 0 | 4 | 0 | 0.007 | 0.944 | 94.877 | 0.243 | 0.144 | 0.280 | 0.225 | 0.153 | 0.000 | 23864.000 | 5174034.000 | 13266.754 | | 50 | POST | /ship | 0 | 40 | 0 | 10 | 0 | 0.004 | 0.948 | 31.514 | 0.630 | 0.016 | 0.829 | 0.849 | 0.361 | 28.000 | 60.000 | 2720.000 | 54.400 | | 38 | POST | /complete | 0 | 37 | 0 | 1 | 0 | 0.008 | 1.117 | 30.578 | 0.805 | 0.192 | 0.844 | 0.888 | 0.228 | 0.000 | 33.000 | 1221.000 | 32.132 | | 128 | GET | /new_items.json | 0 | 128 | 0 | 0 | 0 | 0.212 | 1.509 | 69.956 | 0.547 | 0.212 | 0.372 | 0.369 | 0.185 | 22988.000 | 23744.000 | 2994285.000 | 23392.852 | | 788 | GET | /new_items/\d+.json | 0 | 785 | 0 | 3 | 0 | 0.044 | 1.857 | 214.928 | 0.273 | 0.044 | 0.112 | 0.296 | 0.148 | 0.000 | 24021.000 | 18454159.000 | 23418.984 | | 2932 | GET | /items/\d+.json | 0 | 2932 | 0 | 0 | 0 | 0.008 | 1.857 | 37.309 | 0.013 | 0.080 | 0.004 | 0.012 | 0.040 | 1851.000 | 4052.000 | 6539101.000 | 2230.253 | | 61 | POST | /buy | 0 | 41 | 0 | 20 | 0 | 0.076 | 1.865 | 70.834 | 1.161 | 0.040 | 1.725 | 1.657 | 0.754 | 28.000 | 48.000 | 2118.000 | 34.721 | | 414 | GET | /users/transactions.json | 0 | 409 | 0 | 5 | 0 | 0.024 | 2.341 | 256.159 | 0.619 | 0.216 | 1.160 | 0.340 | 0.411 | 0.000 | 27197.000 | 8797561.000 | 21250.147 | | 1 | POST | /initialize | 0 | 1 | 0 | 0 | 0 | 8.213 | 8.213 | 8.213 | 8.213 | 8.213 | 8.213 | 8.213 | 0.000 | 32.000 | 32.000 | 32.000 | 32.000 | +-------+--------+-------------------------------------+-----+------+-----+-----+-----+-------+-------+---------+-------+-------+-------+-------+--------+------------+------------+--------------+------------+INDEXを張る
items
テーブルのseller_id
、buyer_id
、created_at
にINDEXを張ってみます。還元率を変更してみる
当日はルールへの理解が足りず着手しなかったのですが、
postInitialize
のレスポンスにあるcampaign
の数値を変更することで負荷が上がるようです。
試しに0 → 1に変更してベンチマークを実行した結果が以下のものです。{ "pass": true, "score": 7240, "campaign": 1, "language": "ruby", "messages": [ "GET /new_items.json: リクエストに失敗しました(タイムアウトしました)", "GET /users/transactions.json リクエストに失敗しました (user_id: 3197)(タイムアウトしました)", "POST /login: リクエストに失敗しました(タイムアウトしました)", "POST /ship: リクエストに失敗しました (item_id: 50041)(タイムアウトしました)" ] }タイムアウトが増えますが、スコアは上がっています。
まとめ
1台構成ですが、予選通過ラインに肉薄するスコアが出るようになってきました。
本番の8時間でこれらを実施するのは大変ですが、来年は予選通過できるよう精進したいと思います。
- 投稿日:2019-10-02T18:18:58+09:00
【小学生でもわかる】Ruby のeach文 繰り返し処理
【Ruby】each文 繰り返し処理
sample.rbsubjects = ["こくご","さんすう","りか","しゃかい"] subjects.each do |subject| puts "すきな科目は #{subject}です。" end結果
「すきな科目はこくごです」
「すきな科目はさんすうです」
「すきな科目はりかです」
「すきな科目はしゃかいです」と表示される
解説
1.「subjectsっていう箱の中に4つぶちこむぜ!」
2.「subjectsっていう箱の中から今度は一個ずつ取り出してならべていくぜ!」
3.「そんで取り出すときにはsubjectっていう名前つけるぜ!」というイメージ
【応用編】
sample.rbsamples = [ {subject: "こくご", score: 80, grade: "A"}, {subject: "さんすう", score: 45, grade: "D"}, {subject: "えいご", score: 100, grade: "S", comment: "よくできました!"} ] samples.each do |sample| puts "#{sample[:subject]}のてんすうは#{sample[:score]}点で、ひょうかは#{sample[:grade]}でした" if sample[:comment] puts "コメント: #{sample[:comment]}" end endコメントがあるときだけコメントを表示できるようにするif文を組み込むことができる
- 投稿日:2019-10-02T18:03:58+09:00
【小学生でもわかる】Rubyでの[ ]と{ }の違い 配列とハッシュの違い
【Ruby】 [ ]配列と { }ハッシュの違い
同じ種類の情報をひとまとめにする時(配列)
「教科」という共通の情報を併記
sample.rbsample = ["こくご", "さんすう", "えいご"]1つのことに対して複数の情報を加える時(ハッシュ)
対してこちらは共通の情報を併記しているわけではない。
例えるならa,1,アを一括りにしているイメージsample.rbsample = {"subject" => "こくご", "score" => 80, "grade" => "A"}シンボルを用いる方法
sample.rbsample = {:subject => "こくご", :score => 80, :grade => "A"}この方がキーと値の関係がわかりやすくて良いと思う。
省略形
sample.rbsample = {:subject => "こくご", :score => 80, :grade => "A"} sample = {subject: "こくご", score: 80, grade: "A"}この方がさらにわかりやすいと思う
[ ]と{ } 配列とハッシュの応用
sample.rbsample = {subject: "こくご", score: 80, grade: "A"} samples = [ {subject: "こくご", score: 80, grade: "A"}, {subject: "さんすう", score: 45, grade: "D"}, {subject: "えいご", score: 100, grade: "S"} ]配列の中にハッシュがある状態
- 投稿日:2019-10-02T16:24:35+09:00
cloud9 環境 で rails 5.2.3を初めて設定してみた。
概要
Rubyを学び始めた初学者です。clou9でruby開発環境を整えるまで2日かかってしまいました。rails6.0.0をインストールしてもrailsサーバーが起動できなかった(yarnインストールができず、諦めました。)ため、rails5.2.3で構築してみましたよ。初投稿。
間違っている所などありましたら、ご指摘頂けると嬉しいです。前提条件
amazon web serviceアカウントを持っている方
cloud9環境での開発を考えている方環境
ruby 2.6.5
rails 5.2.3
sqlite3 3.7.17ruby 2.6.5 のインストール
environmentディレクトリにて、コードの実行をする。
インストール可能なruby一覧情報
rvm list know
rubyのインストール
rvm install 2.6.5
複数インストールしたrubyから、選択する
rvm use 2.6.5
インストールされているrubyの内、どれが使われているか確認
rvm list
インストールされているrubyを、選択して削除
rvmsudo rvm remove 2.6.5
インストールした複数のrubyから、デフォルトとして設定
rvm --default use 2.6.5
rails 5.2.3のインストール
environmentディレクトリにて、コードの実行をする。
```gem install rails --version="5.2.3"railsプロジェクトの作成
『プロジェクト名』のフォルダを作成。
以下、コマンドでディレクトリ移動。
cd 『プロジェクト名』
rails _5.2.3_ new フォルダ名
を入力。
『フォルダ名』ディレクトリへ移動。
cd 『フォルダ名』
bundleのインストール
bundle install
sqlite3の更新設定
gemfile→の中→9行目あたりの
sqlite3
の後に,'~>1.3.6'
と入力ターミナルにて、
bundle update
rails db:create
と入力サーバーの起動
ターミナルにて、
rails s
と入力上部タブ『preview』から『preview runnning applecation』を選択
URLを確認。rails スタートの画面になっていれば成功。
- 投稿日:2019-10-02T15:47:13+09:00
Sinatra サーバーを Rakefile とかで起動する
背景
Sinatraでサーバー起動したかったんだが、
rackup
や、bundle exec ruby ~~~
で起動する方法しかググれなかった、、、結論
Rakefileのタスクの中などで、Sinatra::Baseのサブクラスの
run!
を呼ぶoption = {port: 12345} ClassOfSinatraServer.run!(option)経緯と詳細
Sinatraのドキュメントをざっと読んだんだが、
http://sinatrarb.com/intro-ja.html
「モジュラーアプリケーションの提供」あたりにいくつか起動方法が書いてあるんだが、
rubyスクリプトで起動する方法がずばり書いてない、、、(と思う、、)
書いてあったが、わからんかった。(run!
メソッドがprivateなんかと思った)
その他ググったりして、
以下の感じで一応起動したので、メモ作成Gemfilesource "https://rubygems.org" gem 'sinatra'the_server.rbrequire 'sinatra/base' class TheServer < Sinatra::Base get '/' do 'Hello, Sinatra' end endRakefilerequire './the_server.rb' task default: :sinatra_server desc 'start Sinatra server' task :sinatra_server do option = { port: 12345 } TheServer.run!(option) end上記3ファイルを同じフォルダにおいて、そこのフォルダをカレントにして
> bundle > rakeで起動する!
- 投稿日:2019-10-02T15:25:37+09:00
Rails スクレイピングでデータを取得(getメソッド・searchメソッド編)備忘録
スクレイピングとは
- 例えば、以下のようなHTMLのサイトがあった場合
index.html<ul> <li>TEST1</li> <li>TEST2</li> <li>TEST3</li> </ul>
<ul><li>
の中にある「TEST1, TEST2, TEST3」等の値を取り出すことを言う。(ウェブサイト上のHTMLからある特定のデータを抜き出す処理のこと)Mechanize
- Mechanizeはスクレイピングを行うためのGemである。
- Mechanizeクラスが使えるようになる。
- Mechanizeクラスにはスクレイピングするための様々なメソッドが用意されている。
GemfileにMechanizeを追記(Railsの場合)
Gemfile# 省略 gem 'mechanize'bundle installすればOK
Mechanizeクラスで使うメソッドの紹介
HTML情報から指定のタグ要素の情報を検索する
● searchメソッド
- getメソッドで取得したページの情報が入ったオブジェクトに対して使用する。
- 該当するHTMLのタグ要素が1つでも、返り値は配列の形式で返ってくる。
使い方
elements = Mechanize::Pageオブジェクト.search('セレクタ')あるウェブページからh2要素のHTMLの情報を取得する場合
scraping.rbagent = Mechanize.new page = agent.get("http://sample.com/") elements = page.search('h2') # h2要素を検索 puts elements
- 出力結果(例)
<h2 class="entry-title index-entry-title"> <a href="/products/1" title="Single Post">sample1</a> </h2> <h2 class="entry-title index-entry-title"> <a href="/products/2" title="Single Post">sample2</a> </h2> <h2 class="entry-title index-entry-title"> <a href="/products/3" title="Single Post">sample3</a> </h2> #以下略h2要素の下のa要素のHTML情報を取得してみる
scraping.rbagent = Mechanize.new page = agent.get("http://sample.com/") elements = page.search('h2 a') # h2要素の下のa要素を検索 puts elements
- 出力結果(例)
<a href="/products/1" title="Single Post">sample1</a> <a href="/products/2" title="Single Post">sample2</a> <a href="/products/3" title="Single Post">sample3</a> <a href="/products/4" title="Single Post">sample4</a> # 以下略このように、該当するHTMLのタグ要素全てが取得される。
- 以下のようにするとsearchメソッドの返り値が配列の形式になっていることが確認できる。
test_scraping.rbrequire 'mechanize' agent = Mechanize.new page = agent.get("http://sample.com/") elements = page.search('h2 a') # h2要素の下のa要素を検索 puts elements[0]
- 出力結果
ターミナル<a href="/products/1" title="Single Post">Sample1</a>以上のように返ってきた値の1番目の要素を取り出すことができるので配列の形式で返ってきていることがわかる。
まとめ
以上でmechanizeを使用したメソッドのうちgetメソッドとsearchメソッドの2つを紹介しましたが今日は時間切れなので後日、他の使える便利なメソッドを紹介したいと思う。
- 投稿日:2019-10-02T14:22:24+09:00
attr_accessorについて
attr_accessorについて
attr_accesssorは外部からインスタンス変数を参照できるようにするために使用するメソッド。(厳密には、参照と書き込みの両方が行うことができる。)initializeで定義したインスタンス変数を外部から参照または、変更ができるようになる。
ex: attr_accessorの使用例class Product attr_accessor :id def initialize(name) @id = name end def name "#{@id}-Product." end end # => コンソール a=Product.new("sample") => #<Product:0x000056145a7f3d10 @id="sample"> a.name => "sample-Product." #インスタンス変数を参照可能 a.id => "sample" # インスタンス変数を変更可能 a.id = "red" => "red" a.name => "red-Product."#initializeとは?
インスタンスを初期化したいときに実装したい処理を定義する場所。外部から呼び出せない。(デフォがprivateメソッド)引数をつければ、newする時に引数が必要となる。initialize内でインスタンス変数を作成すれば、クラス内でそのまま参照できる。しかし、インスタンス変数を外部から参照はできない。
class Product def initialize(name) @id = name end def name "#{@id}-Product." end end # => コンソール a=Product.new('aa') => #<Product:0x0000558c6c72a508 @id="aa"> a.name => "aa-Product." # 外部からの参照はできない a.id => NoMethodError: undefined method 'id'initializeを使用せずにクラスを作成してみた。
initializeがないため引数をつけるとエラーが出る。初期化時の実行が定義されていないため!
引数なしで作成し、インスタンス変数に値を代入すれば、メソッドでもインスタンス変数をして出力できた。class Product attr_accessor :id def name "#{@id}-Product." end end # => コンソール # 引数をつけるとエラーが出る a=Product.new("sample") ArgumentError: wrong number of arguments (given 1, expected 0) # 引数なしなら作成できる a=Product.new => #<Product:0x000055eca644b478> # 値を代入していないためnil a.id => nil a.name => "-Product." # attr_accessorがあるため、代入は可能 a.id = "sample" => "sample" # 代入後はメソッドなども問題なく使用できる a.id => "sample" a.name => "sample-Product."
- 投稿日:2019-10-02T14:13:31+09:00
再帰してディレクトリ内のファイルの行数を個別に表示する
末尾が
_spec
のファイルは除外している# 全ファイルの行数を吐き出すlinuxコマンド (rubyはバッククォートにするとシェルを直接実行できる) `for file in $(find . -name "*.rb"); do wc -l $file; done > ./tmp/lines.txt` open('./tmp/lines.txt', 'r') { |f| f.inject([]) { |r, l| r << l.split(" ") } }.sort{|a, b| a[0].to_i <=> b[0].to_i }.each {|i| puts i.join(" : ") unless i[1] =~ /_spec/ }よくよく考えたらシェル使わずに
Dir.glob
でパス取ってきてやるでもよかったな...
- 投稿日:2019-10-02T12:25:13+09:00
RubyでNokogiriを使ってスクレイピングを行う
Nokogiriを使って、スクレイピングしてcsvに吐き出す方法
cssを使って指定
row.css('#normalResultsBox') #ID row.css('.normalResultsBox') #クラス row.css('h4>a').text, #階層 row.css('p')[1].text #2番目要素 row.css('a').attribute('href').value #タグ内の要素を取得 row.css('a').gsub('aaaa','') #置換する row.css('a').split(".")[0] #区切って1番目を取得Rubyプログラミング
test.rb#住所という文字列が存在するかどうか if row.css('p')[0].text.include?("住所") #存在する else #存在しない endurlからスクレイピング
noko.rbrequire 'nokogiri' require 'open-uri' require 'csv' #ヘッダーの書き込み CSV.open('noko.csv', 'w') do |csv| csv << ["title","url"] end #スクレイピングするurlを列挙する urls = [ 'url1', 'url2' ] #urlをループ処理 urls.each { |url| charset = nil html = open(url) do |f| f.read end doc = Nokogiri::HTML.parse(html, nil, "CP932") #2時配列を宣言する arr = Array.new doc.css('.normalResultsBox').each do |row| arr << [ row.css('h4>a').text, #タイトル row.css("a").attribute('href').value #url ] end # csvファイル形式で生成 string_csv_format = CSV.generate do |data| arr.each do |line| data << line end end # csvファイル書き出し方法1 File.open("noko.csv", "a") do |f| f.puts string_csv_format end }textファイルを読み込んで、取り出す
noko2.rbrequire 'nokogiri' require 'csv' #ヘッダーの書き込み CSV.open('itown.csv', 'w') do |csv| csv << ["url","comment"] end html = File.open("test1.txt") do |f| f.read end doc = Nokogiri::HTML.parse(html, nil, "CP932") #2時配列を宣言する arr = Array.new doc.css('.normalResultsBox').each do |row| arr << [ row.css('h4>a').text, #社名 row.css('p')[1].text.gsub('住所 ','').gsub('〒','').split(" ")[0], #郵便番号 row.css('p')[1].text.gsub(' 地図・ナビ','').split(" ")[1], #住所 row.css('p')[2].css('b').text #電話 ] end # csvファイル形式で生成 string_csv_format = CSV.generate do |data| arr.each do |line| data << line end end # csvファイル書き出し方法1 File.open("itown.csv", "a") do |f| f.puts string_csv_format end実行する
$ruby noko.rb
- 投稿日:2019-10-02T12:21:19+09:00
Rails6 のちょい足しな新機能を試す87(Time#advance編)
はじめに
Rails 6 に追加された新機能を試す第87段。 今回は、
Time#advance
編です。
Rails 6 では、 1001/03/07 以前のTime#advance
の計算が正確になりました。Ruby 2.6.4, Rails 6.0.0 Rails 5.2.3 で確認しました。
$ rails --version Rails 6.0.0今回は、ちょっとわざとらしいですが、2009年4月1日の1200年前に即位した天皇を検索してみましょう。
プロジェクトを作る
rails new rails_sandbox cd rails_sandbox
Emperor モデルを作る
name
とenthroned_at
(即位した年) をもつEmperor
モデルを作ります。bin/rails g model Emperor name enthroned_at:datetimeseed データを作る
seed
データを作ります。db/seeds.rbEmperor.create( [ { name: '桓武天皇', enthroned_at: Time.utc(781, 4, 3) }, { name: '平城天皇', enthroned_at: Time.utc(806, 3, 17) }, { name: '嵯峨天皇', enthroned_at: Time.utc(809, 4, 1) }, { name: '淳和天皇', enthroned_at: Time.utc(823, 4, 16) }, { name: '仁明天皇', enthroned_at: Time.utc(833, 2, 28) } ] )マイグレーションを行い seed データを登録する
$ bin/rails db:create db:migrate db:seed
rails console で確認する
enthroned_at
が 2009年4月1日の 1200年前に即位した天皇を検索してみます。「2009年4月1日の 1200年前」は、
Time.utc(2009, 4, 1).advance(years: 1200)
で求めることができます。irb(main):001:0> Emperor.where(enthroned_at: Time.utc(2009, 4, 1).advance(years: -1200)) Emperor Load (0.3ms) SELECT "emperors".* FROM "emperors" WHERE "emperors"."enthroned_at" = $1 LIMIT $2 [["enthroned_at", "0809-04-01 00:00:00"], ["LIMIT", 11]] => #<ActiveRecord::Relation [#<Emperor id: 3, name: "嵯峨天皇", enthroned_at: "0809-04-01 00:00:00", created_at: "2019-09-21 21:49:24", updated_at: "2019-09-21 21:49:24">]>嵯峨天皇が検索できました。
Rails 5.2.3 では
「2009年4月1日の 1200年前」が 809年4月5日になってしまうため、期待した結果が得られません
irb(main):001:0> Emperor.where(enthroned_at: Time.utc(2009, 4, 1).advance(years: -1200)) Emperor Load (0.5ms) SELECT "emperors".* FROM "emperors" WHERE "emperors"."enthroned_at" = $1 LIMIT $2 [["enthroned_at", "0809-04-05 00:00:00"], ["LIMIT", 11]] => #<ActiveRecord::Relation []>試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try087_time_advance参考情報
- 投稿日:2019-10-02T12:07:01+09:00
Railsアプリ〜デプロイへの道〜その②Ruby・MySQLインストール編【ConoHa VPS・CentOS・Capistrano3・Nginx・Unicorn】
Railsアプリケーションをデプロイした時の手順をまとめた記事の第2弾です。
今回はRubyおよびMySQLのインストール・設定の手順をまとめました。
前回同様こちらの記事がベースとなっています。
https://qiita.com/ryo2132/items/f62690f0b16ec11270fe〈前回記事〉
Railsアプリ〜デプロイへの道〜その①リモートサーバーへのSSH接続編開発環境
・Mac OS
・Rails 5.2.3
・Ruby 2.5.1
・ConoHa VPS
・CentOS 7.6
・Capistrano3
・Nginx
・UnicornRubyのインストール
ConoHa VPSにRubyをインストールしていきます。
1.Gitインストール
まずGitをインストールします。
$ sudo yum -y install git $ git --version # version名出力されればOK2.rbenvインストール
続いてrbenvをインストール。
rbenvはRubyのバージョン管理ツールです。$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenvruby-burildインストール
こちらもRubyをインストールするために必要になります。
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build3.rbenv設定
rbenvコマンドを使えるようにするためにbash_profileに以下の内容を追加します。
# PATHにrbenvコマンドを追加 $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile # rbenvの初期化 $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile # bashの再読込 $ source ~/.bash_profile # rbenvのバージョン確認 バージョンが出ればOK $ rbenv -vこれでRubyインストールの準備は完了です。
いよいよRubyをインストールします。4.Rubyインストール
ローカルで使用中のRubyバージョンを確認
サーバーにインストールする前に、開発で使用したRubyのバージョンを確認します。ローカル
$ ruby -vローカルと同じバージョンのRubyをインストール
サーバー
$ rbenv install 2.5.1 # globalで使用するrubyの設定 $ rbenv global 2.5.1 # rbenvの再起動? $ rbenv rehash # rubyのバージョン確認 $ ruby -v5.bundleインストール
Gemの管理ツールであるbundlerをインストールします。
bundlerのバージョンを開発したRailsアプリのGemfile.lockのものと合わせる必要があります。
バージョンが合っていないとデプロイ時にエラーが発生します。
参考:https://qiita.com/MotohiroSiobara/items/c0d343a160cffc2902efRailsアプリのGemfile.lockを確認
BUNDLED WITH 2.0.1サーバー
同じバージョンのbundlerをインストール。$ gem install bundle -v 2.0.16.関連パッケージインストール
必要なパッケージを諸々インストール
これらがないとデプロイ時にエラー起こします。<参考>
https://teratail.com/questions/13430
https://qiita.com/jaxx2104/items/2277cec77850f2d83c7aサーバー
#gcc-c++インストール $ sudo yum install gcc-c++ #node.jsインストール $ sudo yum install nodejs npm --enablerepo=epel #yarnインストール $ sudo npm install -g yarnMySQL
1.事前準備:MariaDBの削除
CentOS7系では標準でMariaDB(MySQL互換のDB)がインストールされている場合があるので、MySQLと競合しないようMariaDBを削除します。
参考:https://qiita.com/miqpim/items/5c519a9979d9b269d47e
サーバー
$ rpm -qa | grep maria # mariaDBが存在するか確認 $ sudo yum remove mariadb-libs # 本体削除 $ sudo rm -rf /var/lib/mysql # データ削除rmコマンドのオプションについてはこちらをご覧ください。
参考:https://eng-entrance.com/linux_command_rm2.MySQLのリポジトリを登録
Mysql公式のYumリポジトリをインストールします。
最新版はMysql公式で確認できます。サーバー
〈参考〉
https://qiita.com/rutko/items/56a33d1ecd70c0480202
https://qiita.com/nooboolean/items/7efc5c35b2e95637d8c1CentOSのバージョンの確認
$ cat /etc/redhat-releaseリポジトリのインストール
yumコマンドのlocalinstallオプションを使うことでリモートにあるrpmファイルをインストールすることができます。
rpmコマンドを使ってのインストールも可能ですが、依存関係とかを考慮したインストールまではしてくれないので、yumでインストールしましょう。
URLはリモートにあるrpmファイルをインストールするためのもので、公式サイトのリポジトリを、http://dev.mysql.com/get/
の後に付け加えて完成です。(お使いのOSに合わせたものを選んでください)詳しくはこちらの記事をご覧ください。
https://qiita.com/nooboolean/items/7efc5c35b2e95637d8c1$ sudo yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpmリポジトリの確認
/etc/yum.repos.d配下に、mysql-community-source.repoとmysql-community.repoというリポジトリが作成されてるはずです。
$ cd /etc/yum.repos.d/ $ ls mysql-community-source.repo mysql-community.repoこのリポジトリが作成されて入れば、リポジトリの追加の確認は完了
インストールできたか確認
$ yum repolist all | grep mysql mysql-connectors-community/x86_64 MySQL Connectors Community 有効: mysql-connectors-community-source MySQL Connectors Community - So 無効 mysql-tools-community/x86_64 MySQL Tools Community 有効: mysql-tools-community-source MySQL Tools Community - Source 無効 mysql55-community/x86_64 MySQL 5.5 Community Server 無効 mysql55-community-source MySQL 5.5 Community Server - So 無効 mysql56-community/x86_64 MySQL 5.6 Community Server 無効 <-ここ注目 mysql56-community-source MySQL 5.6 Community Server - So 無効 mysql57-community/x86_64 MySQL 5.7 Community Server 有効: <-ここ注目 mysql57-community-source MySQL 5.7 Community Server - So 無効(環境によっては有効がenabled、無効がdisabledと表示される) 上記の例では、5.7が有効、5.6が無効になっています。 このままインストールすると、有効になっている5.7がインストールされてしまうので、5.6をインストールするには有効無効の切り替えをします。 この切り替えをするためにはyumの設定変更用のyum-utilsパッケージが必要なので、インストールされていない場合はインストールします。
$ yum list installed | grep yum-utils #yum-utilsがインストールされているか確認 $ yum -y install yum-utils #入ってなければyum-utilsをインストールする $ yum-config-manager --disable mysql57-community #5.7を無効に設定 $ yum-config-manager --enable mysql56-community #5.6を有効に設定設定ができているか再度確認。
$ yum repolist all | grep mysql mysql-connectors-community/x86_64 MySQL Connectors Community 有効: mysql-connectors-community-source MySQL Connectors Community - Sou 無効 mysql-tools-community/x86_64 MySQL Tools Community 有効: mysql-tools-community-source MySQL Tools Community - Source 無効 mysql55-community/x86_64 MySQL 5.5 Community Server 無効 mysql55-community-source MySQL 5.5 Community Server - Sou 無効 mysql56-community/x86_64 MySQL 5.6 Community Server 有効: mysql56-community-source MySQL 5.6 Community Server - Sou 無効 mysql57-community/x86_64 MySQL 5.7 Community Server 無効 mysql57-community-source MySQL 5.7 Community Server - Sou 無効5.6が有効になっていればOK。
#バージョン確認 $ yum info mysql-community-server # インストール $ sudo yum install mysql-community-server mysql-develmysql-develは必要です。
ないとデプロイ時にエラーが出ます。
参考:https://teratail.com/questions/181707# 確認。バージョン出ればOK $ mysqld --versionMysqlの起動/自動起動設定
起動
$ sudo systemctl start mysqld.service #起動自動起動設定
$ sudo systemctl enable mysqld.service #自動起動 ON $ systemctl disble mysqld #自動起動 OFF自動起動になっているか確認
$ systemctl is-enabled mysqld mysqld.service is not a native service, redirecting to /sbin/chkconfig. Executing /sbin/chkconfig mysqld --level=5 enabledenabledになっていれば自動起動 ONに設定されています。
基本操作
$ sudo systemctl start mysqld.service #起動 $ systemctl stop mysqld #停止 $ systemctl status mysqld #ステータス確認 $ systemctl restart mysqld #再起動ちなみに、mysqldのdはデーモン (daemon)のdらしいです。
デーモンについてはこちらの記事をご覧ください。
https://wa3.i-3-i.info/word11000.html簡単に言うと「いつでも動けるようにスタンバイしてる常駐プログラム」だそうです。
3.パスワード、セキュリティ設定
続いてMySQLの設定をしていきます。
今回の山場です。
参考:https://weblabo.oscasierra.net/mysql-57-init-setup/ログインするために、まず自動生成された初期パスワードを確認します。
$ sudo cat /var/log/mysqld.log | grep password 2017-12-31T11:31:07.946947Z 1 [Note] A temporary password is generated for root@localhost: .7ogGO4yokDh # 「.7ogGO4yokDh」の部分が初期パスワードです確認できたらmysql_secure_installationで初期設定を行います。 以下対話形式で進むので適宜コマンド入力してください。
$ mysql_secure_installation Securing the MySQL server deployment. Enter password for user root: # ログファイルから取得した初期パスワードを入力します The existing password for the user account root has expired. Please set a new password. New password: # root ユーザの新規パスワードを入力します Re-enter new password: # 確認用にもう一度入力します The 'validate_password' plugin is installed on the server. The subsequent steps will run with the existing configuration of the plugin. Using existing password for root. Estimated strength of the password: 100 Change the password for root ? ((Press y|Y for Yes, any other key for No) : y By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? (Press y|Y for Yes, any other key for No) : y # 匿名ユーザーアカウントを削除 Success. Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y # ローカルホスト以外からアクセス可能な root アカウントを削除 Success. By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y # test データベースの削除 - Dropping test database... Success. - Removing privileges on test database... Success. Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y Success. All done!4.日本語化
日本語を扱うために文字コードを設定します。
日本語の文字コードはutf8に設定すると思いますが、utf8mb4は絵文字に対応した文字コードなので、僕はutf8ではなくutf8mb4で設定しています。現状、問題なく使えています。
〈参考〉
https://qiita.com/okamu_/items/5eb81688849fbe351350
https://qiita.com/jkr_2255/items/74fc79e764378b59355a$ sudo vi /etc/my.cnf #ファイル内の末尾に以下を追記 [mysqld] character-set-server=utf8mb4 [client] default-character-set=utf8mb4 #再起動 $ sudo systemctl restart mysqld.service #文字コード確認 $ mysql -u root -p $ show variables like "chara%";utf8mb4になってたらOK!
5.Time-zone設定
〈参考〉
https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html
https://agohack.com/mysql-change-timezone/現在のタイムゾーンを確認
$ show variables like '%time_zone%'; system_time_zone : UTC time_zone : SYSTEMタイムゾーンデータの確認
$ select * from mysql.time_zone;空の場合は、データをインポートする。
タイムゾーンのインポート
$ /usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo > ~/timezone.sql # passwordを聞かれるのでmysqlのパスワードを入力 $ mysql -u root -p -Dmysql < ~/timezone.sql設定の追加
$ sudo vi /etc/my.cnf # 末尾に以下を追加 [mysqld] default-time-zone = 'Asia/Tokyo'再起動
$ sudo systemctl restart mysqld.service確認
mysql > show variables like '%time_zone%'; # 以下表示が出ればOK +------------------+------------+ | Variable_name | Value | +------------------+------------+ | system_time_zone | JST | | time_zone | Asia/Tokyo | +------------------+------------+ 2 rows in set (0.00 sec)MySQLの自動起動設定
サーバーの再起動の際にも、mysqlが自動的に起動するよう設定します。chkconfig mysqld onまとめ
以上、Railsアプリ〜デプロイへの道〜その②Ruby・MySQLインストール編でした。
次回はいよいよCapistrano3・Nginx・Unicornの設定です。(予定)
- 投稿日:2019-10-02T11:49:41+09:00
brewで入れているruby-buildをgitのHEADに更新する
はじめに
久々のQiitaです。
Rubyの2.4以降のバージョンに対してセキュリティリリースが出たそうで。
https://www.ruby-lang.org/ja/news/2019/10/01/ruby-2-6-5-released/使っているrubyのバージョンを更新しようとしたところ、
brew upgrade ruby-build
したのに2.6.5がない。$ brew update && brew upgrade ruby-build $ rbenv install --list ...(中略)... 2.6.3 2.6.4 2.7.0-dev 2.7.0-preview1 ...(中略)...どうやら
brew upgrade ruby-build
でインストールできるのは2019/08/28
リリースのバージョンまでらしい(2019/10/02現在)。
https://formulae.brew.sh/formula/ruby-buildというわけで、gitのHEADから拾ってきて
ruby-build
を更新します。やり方
インストールコマンドにオプションを付けるだけ
$ brew install ruby-build --HEADが、既に
ruby-build
が入った状態でこれをやると怒られます。Error: ruby-build 20190828 is already installed To install HEAD, first run `brew unlink ruby-build`. Warning: Skipping (old) /usr/local/Cellar/ruby-build/20190828 due to it being linkedまあそりゃそうだ、ということで、一旦
unlink
して外してあげてから再インストールします。$ brew unlink ruby-build $ brew install ruby-build --HEADRubyのインストールをしたらバージョン切り替えて確認
$ rbenv install 2.6.5 $ rbenv local 2.6.5 $ ruby -v ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]大丈夫そうっすね。
というわけで以上です〜〜参考
- 投稿日:2019-10-02T11:13:46+09:00
Rails6でのRubyOnRails 環境構築
はじめに
RubyOnRailsの導入方法です。
エラーが起こってわかりにくかったところをまとめます。開発環境等
- macOS Mojave version 10.14.6
- Ruby 2.6.4
- Rails 6.0.0
- rbenv local 2.6.4
- sqlite3 3.29.0
Homebrewのインストール
入っていない人は次のコマンドをコピペしてインストールしてください。
Homebrewのインストール$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"次にHomebrewをupdateします
Homebrewのアップデート$ brew updaterbenvのインストール
rbenvを使うと複数のバージョンのrubyを管理できるようになります。
ruby-buildはRubyをバージョンごとに異なるディレクトリにビルドするためのツールrvenvのインストール$ brew install rbenv ruby-build環境変数のPATHにディレクトリを登録しておくと登録したディレクトリ直下のスクリプトが絶対パスで指定しなくても実行できるようになります。
.bash_profileの設定$ echo 'export PATH="~/.rbenv/shims:/usr/local/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profileRuby2.6.4のinstall
インストールできるrubyのバージョンを確認する
バージョンの確認$ rbenv install -l僕はruby2.6.4が最新だったのでそれをインストールしました。
ruby2.6.4のinstall$ rbenv install 2.6.4システム全体でつかうRubyとして登録して置きたいのでそれも設定
$ rbenv global 2.6.4インストールしたRubyを使用可能にするためにrehash
$ rbenv rehash複数のバージョンをインストールする場合は繰り返しコマンドの実行を行う
Railsのinstall
RailsはWebアプリケーションフレームワークです。これもインストールしていきます
(注:2.5.0以降のVersionでしかRailsは動きません!!!)1.bundlerのインストール
まずbundlerをインストールします。gemコマンドではなくbundlerコマンドでパッケージをインストールすることでバージョンの互換性の問題を解決できます。
PermissionError言われたのでsudoさん使って実行
bundlerのインストール$ sudo gem install bundler2.sqlite3のアップグレード
Railsを利用するためにはsqlite3をインストールしている必要があります。macにはデフォルトで入っているのでアップグレードします。あとはシンボリックリンクを作成してパスを通す。
RailsのデフォルトのDBはsqliteですのでmysqlを使いたい人は切り替えて使う。//現在のバージョンの確認 $ sqlite3 --version 3.24.0 //sqlite3のアップグレード $ brew upgrade sqlite3 //最新バージョンの確認 $ ls /usr/local/Cellar/sqlite/ 3.29.0 //シンボリックリンクの作成 $ cd /usr/local/bin/ $ ln -sf ../Cellar/sqlite/3.29.0/bin/sqlite3 ./ //PATHを通す $ echo 'export PATH=/usr/local/bin:"$PATH"' >> ~/.bash_profile $ source ~/.bash_profile //変更できたか確認 $ sqlite3 --version 3.29.03.作業用ディレクトリへのgemのインストール
作業用ディレクトリの作成を行う
作業用ディレクトリの作成$ mkdir ~/workspace $ cd ~/workspaceRubyのバージョンの指定
$ rbenv local 2.6.4ruby '~> 2.6.4'を追加し、Gemfileのgem "rails"の コメントアウトを外す(バージョンは自分が入れたバージョンに変える)
GemFileの作成$ bundle init Writing new Gemfile to /Users/<ユーザ名>/workspace/GemfileGemfileの編集$ vim /Users/<ユーザ名>/workspace/Gemfile ruby '~> 2.6.4' # frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "rails"railsをインストールする
Railsのインストール$ bundle install --path=vendor/bundle $ bundle exec rails -v Rails 5.2.3bundle install --path=vendor/bundleでバージョンエラーが起こる場合の対処方法
試しにブログアプリケーションを作成して動作確認を行ったところbundleがsystemのrubyを参照していたため失敗。雑だがファイルを無理やり移動させてパスを変更したらうまくいった。
bundleとbundlerのPATH $ which bundle bundler /usr/local/bin/bundle /usr/local/bin/bundler 変更 $ mv /usr/local/bin/bundle /Users/<ユーザ名>/.rbenv/shims/bundle $ mv /usr/local/bin/bundler /Users/<ユーザ名>/.rbenv/shims/bundler $ which bundle bundler /Users/<ユーザ名>/.rbenv/shims/bundle /Users/<ユーザ名>/.rbenv/shims/bundler4.サーバーの起動
Rails6を使う場合は# environment is not defined in config/webpacker.ymlが出る時を行う。場合によってはcan't find gem railtiesが出る時を行う。
サーバーの起動$ bundle exec rails new blog $ cd ~/workspace/blog $ rails server<img width="752" alt="スクリーンショット 2019-10-02 2.10.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505843/cdbc5838-e114-0e7a-ea42-a258ae3cc5fc.png"> <img width="752" alt="スクリーンショット 2019-10-02 2.10.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505843/47e9ad5d-4e44-f551-6387-49bbf56b0f5b.png"> => Booting Puma => Rails 6.0.0 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 3.12.1 (ruby 2.6.4-p104), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stopcan't find gem railtiesが出る時
パスを変えて実行したところ can't find gem railtiesと言われたのでreailtiesのインストールを行った。
一覧表示$ gem listreailtiesがなければgemでrailsをインストールする。
railsのインストール$ gem install railsenvironment is not defined in config/webpacker.ymlが出る時(Rails6を使う場合必須)
Rails6.0.0ではwebpackerのインストールが必要。インストールしていない場合はenvironment is not defined in config/webpacker.ymlとエラーが出るはず。webpackerのインストールにはyawnのインストールが必要となるのでインストールしていない場合はこちらも。
yawnのインストール$ brew install yawnwebpackerのインストール$ bundle exec rails webpacker:install
http://localhost:3000/ にアクセスしてYay! You’re on Rails!の画面が表示されRuby versionが2.6.4かどうか確認
参考サイト
Ruby初学者のRuby On Rails 環境構築【Mac】
Rails をはじめよう - Railsガイド
Bundlerの使い方
MacのpyenvでHomebrewからインストールしたsqlite3を利用する
- 投稿日:2019-10-02T11:13:46+09:00
Rails6でのRubyonRails環境構築
はじめに
RubyOnRailsの導入方法です。
エラーが起こってわかりにくかったところをまとめます。開発環境等
- macOS Mojave version 10.14.6
- Ruby 2.6.4
- Rails 6.0.0
- rbenv local 2.6.4
- sqlite3 3.29.0
Homebrewのインストール
入っていない人は次のコマンドをコピペしてインストールしてください。
Homebrewのインストール$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"次にHomebrewをupdateします
Homebrewのアップデート$ brew updaterbenvのインストール
rbenvを使うと複数のバージョンのrubyを管理できるようになります。
ruby-buildはRubyをバージョンごとに異なるディレクトリにビルドするためのツールrvenvのインストール$ brew install rbenv ruby-build環境変数のPATHにディレクトリを登録しておくと登録したディレクトリ直下のスクリプトが絶対パスで指定しなくても実行できるようになります。
.bash_profileの設定$ echo 'export PATH="~/.rbenv/shims:/usr/local/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profileRuby2.6.4のinstall
インストールできるrubyのバージョンを確認する
バージョンの確認$ rbenv install -l僕はruby2.6.4が最新だったのでそれをインストールしました。
ruby2.6.4のinstall$ rbenv install 2.6.4システム全体でつかうRubyとして登録して置きたいのでそれも設定
$ rbenv global 2.6.4インストールしたRubyを使用可能にするためにrehash
$ rbenv rehash複数のバージョンをインストールする場合は繰り返しコマンドの実行を行う
Railsのinstall
RailsはWebアプリケーションフレームワークです。これもインストールしていきます
(注:2.5.0以降のVersionでしかRailsは動きません!!!)1.bundlerのインストール
まずbundlerをインストールします。gemコマンドではなくbundlerコマンドでパッケージをインストールすることでバージョンの互換性の問題を解決できます。
PermissionError言われたのでsudoさん使って実行
bundlerのインストール$ sudo gem install bundler2.sqlite3のアップグレード
Railsを利用するためにはsqlite3をインストールしている必要があります。macにはデフォルトで入っているのでアップグレードします。あとはシンボリックリンクを作成してパスを通す。
RailsのデフォルトのDBはsqliteですのでmysqlを使いたい人は切り替えて使う。//現在のバージョンの確認 $ sqlite3 --version 3.24.0 //sqlite3のアップグレード $ brew upgrade sqlite3 //最新バージョンの確認 $ ls /usr/local/Cellar/sqlite/ 3.29.0 //シンボリックリンクの作成 $ cd /usr/local/bin/ $ ln -sf ../Cellar/sqlite/3.29.0/bin/sqlite3 ./ //PATHを通す $ echo 'export PATH=/usr/local/bin:"$PATH"' >> ~/.bash_profile $ source ~/.bash_profile //変更できたか確認 $ sqlite3 --version 3.29.03.作業用ディレクトリへのgemのインストール
作業用ディレクトリの作成を行う
作業用ディレクトリの作成$ mkdir ~/workspace $ cd ~/workspaceRubyのバージョンの指定
$ rbenv local 2.6.4ruby '~> 2.6.4'を追加し、Gemfileのgem "rails"の コメントアウトを外す(バージョンは自分が入れたバージョンに変える)
GemFileの作成$ bundle init Writing new Gemfile to /Users/<ユーザ名>/workspace/GemfileGemfileの編集$ vim /Users/<ユーザ名>/workspace/Gemfile ruby '~> 2.6.4' # frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "rails"railsをインストールする
Railsのインストール$ bundle install --path=vendor/bundle $ bundle exec rails -v Rails 5.2.3bundle install --path=vendor/bundleでバージョンエラーが起こる場合の対処方法
試しにブログアプリケーションを作成して動作確認を行ったところbundleがsystemのrubyを参照していたため失敗。雑だがファイルを無理やり移動させてパスを変更したらうまくいった。
bundleとbundlerのPATH $ which bundle bundler /usr/local/bin/bundle /usr/local/bin/bundler 変更 $ mv /usr/local/bin/bundle /Users/<ユーザ名>/.rbenv/shims/bundle $ mv /usr/local/bin/bundler /Users/<ユーザ名>/.rbenv/shims/bundler $ which bundle bundler /Users/<ユーザ名>/.rbenv/shims/bundle /Users/<ユーザ名>/.rbenv/shims/bundler4.サーバーの起動
Rails6を使う場合は# environment is not defined in config/webpacker.ymlが出る時を行う。場合によってはcan't find gem railtiesが出る時を行う。
サーバーの起動$ bundle exec rails new blog $ cd ~/workspace/blog $ rails server<img width="752" alt="スクリーンショット 2019-10-02 2.10.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505843/cdbc5838-e114-0e7a-ea42-a258ae3cc5fc.png"> <img width="752" alt="スクリーンショット 2019-10-02 2.10.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505843/47e9ad5d-4e44-f551-6387-49bbf56b0f5b.png"> => Booting Puma => Rails 6.0.0 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 3.12.1 (ruby 2.6.4-p104), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stopcan't find gem railtiesが出る時
パスを変えて実行したところ can't find gem railtiesと言われたのでreailtiesのインストールを行った。
一覧表示$ gem listreailtiesがなければgemでrailsをインストールする。
railsのインストール$ gem install railsenvironment is not defined in config/webpacker.ymlが出る時(Rails6を使う場合必須)
Rails6.0.0ではwebpackerのインストールが必要。インストールしていない場合はenvironment is not defined in config/webpacker.ymlとエラーが出るはず。webpackerのインストールにはyawnのインストールが必要となるのでインストールしていない場合はこちらも。
yawnのインストール$ brew install yawnwebpackerのインストール$ bundle exec rails webpacker:installhttp://localhost:3000/ にアクセスしてYay! You’re on Rails!の画面が表示されRuby versionが2.6.4かどうか確認
参考サイト
Ruby初学者のRuby On Rails 環境構築【Mac】
Rails をはじめよう - Railsガイド
Bundlerの使い方
MacのpyenvでHomebrewからインストールしたsqlite3を利用する
- 投稿日:2019-10-02T09:46:46+09:00
canvasで描いた絵のURLをDBに保存する
概要
私は9月ごろから独学でRuby on Railsを始めたのですが、題名の通りcanvasで描いた絵をURLに変換してDBに保存する際に数日詰まったので自分への戒めのために今回の記事を書く運びとなりました。
詰まったところ
ArgumentError (When assigning attributes, you must pass a hash as an argument.):
ハッシュにしてから受け渡してください的なエラーが出る。
受け渡したデータ
JavaScriptでcanvasのデータをURL化しているため、そのままJavaScriptでPOSTしました。
こんなかんじ//変数imageにはcanvasのURLが入っています function send_url(image){ var form = document.createElement('form'); var request = document.createElement('input'); form.method = 'POST'; form.action = 'save'; request.type = 'hidden'; request.name = 'text'; request.value = image; form.appendChild(request); document.body.appendChild(form); form.submit(); }受け取り側はこのようになっています
private def post_params params.require(:text) end endこの形式で受け取るとpost_paramsは送信されてきた文字列だけをデータに持ちます。
修正後
先ほどの関数post_paramsを次のように書き換えました
def post_params img = params.require(:text) hash_url = {"image_url" => img} return hash_url end力技です。
最後に
セキュリティなどの観点で見てこれが大丈夫なやり方なのかはわかりませんが、とりあえずこのハッシュにしたデータを渡すことで無事URLをDBに渡すことができました。