- 投稿日:2019-09-15T23:46:26+09:00
Rubyにおけるクラス/モジュール定義関連の仕組みと、Ruby on Railsにおけるautoloadの仕組み
Ruby における話
モジュールとクラスの違い
モジュールとクラスの違いとして次の項目が挙げられます。
- どちらもクラスインスタンス(またはモジュールインスタンス)を作れる
- どちらもメソッドを定義できる
- モジュールはオブジェクトを作れない
- クラスはオブジェクトを作れる
irb(main):001:0> module Parent irb(main):002:1> class Child irb(main):003:2> end irb(main):004:1> end => nil # どちらもクラスインスタンスを作れる irb(main):005:0> Parent.class => Module irb(main):006:0> Parent::Child.class => Class # モジュールはオブジェクトを作れない irb(main):008:0> Parent.new Traceback (most recent call last): 2: from /home/vagrant/.rbenv/versions/2.5.5/bin/irb:11:in `<main>' 1: from (irb):8 NoMethodError (undefined method `new' for Parent:Module) # クラスはオブジェクトを作れる irb(main):009:0> Parent::Child.new => #<Parent::Child:0x00005587aeab9c90>モジュールとクラスが定義されると Object に定数が追加される
モジュールやクラスが定義済であるかどうかを判別する方法として
defined?
メソッドがあります。未定義の場合は
defined?
はnil
を返し、定義されていると"constant"
を返します。# モジュールが未定義の場合、defined? は nil を返し、定義済の場合は "constant" を返す $ irb irb(main):001:0> defined?(Hoge) => nil irb(main):002:0> module Hoge; end => nil irb(main):003:0> defined?(Hoge) => "constant" # クラスの場合も同様 $ irb irb(main):001:0> class Hoge; end => nil irb(main):002:0> defined?(Hoge) => "constant"ここで、定義済の場合に "constant" が返ることと関連がありますが、モジュールとクラスが定義された時に ruby 内部では Object クラスインスタンスに定数(constant) が追加され、定義されたモジュールまたはクラスのクラスインスタンスが値として格納されます。
# モジュールが定義されると Object クラスインスタンスに定数が追加され、クラスインスタンスが値として格納される $ irb irb(main):001:0> Object.const_get("Hoge") Traceback (most recent call last): 2: from /home/vagrant/.rbenv/versions/2.5.5/bin/irb:11:in `<main>' 1: from (irb):1 NameError (uninitialized constant Hoge) irb(main):002:0> module Hoge; end => nil irb(main):003:0> Object.const_get("Hoge") => Hoge irb(main):004:0> Object.const_get("Hoge").class => Module # クラスの場合も同様 $ irb irb(main):001:0> class Hoge; end => nil irb(main):002:0> Object.const_get("Hoge") => Hoge irb(main):003:0> Object.const_get("Hoge").class => Classクラスやモジュールがネストされた場合は
::
が繋がった名前になります。
また Object クラスインスタンスの他に、子となるクラスやモジュールが定義されると、親となるクラスインスタンスにも定数として定義されます。irb(main):001:0> module Parent irb(main):002:1> class Child irb(main):003:2> end irb(main):004:1> end => nil irb(main):005:0> defined?(Parent::Child) => "constant" irb(main):006:0> Object.const_get('Parent::Child') => Parent::Child irb(main):007:0> Parent.const_get('Child') => Parent::Childこのようにモジュールやクラスが定義されると Object クラスインスタンスに定数が追加され、
defined?
メソッドやObject.const_get("Hoge")
を実行することで定義済であるかどうかを確認することが出来ます。
- クラスやモジュールが未定義である場合
defined?
がnil
を返すObject.const_get
は NameError となる- クラスやモジュールが定義されている場合
defined?
が"constant"
を返すObject.const_get
がクラスインスタンスを返すrequire と load の違い
require
は外部ファイルに記載された ruby コードを読み込むことが出来るメソッドです。(module メソッドは Kernel モジュールで定義されています(参考))クラスやモジュールが定義されている場合は、
require
を実行することで定義されたものが使えるようになります。
require
するファイルにp
メソッド等の、文字列を出力するコードが書かれている場合は実行されます。print.rbclass Print end p "print.rb"$ irb irb(main):001:0> Print Traceback (most recent call last): 2: from /home/vagrant/.rbenv/versions/2.5.5/bin/irb:11:in `<main>' 1: from (irb):1 NameError (uninitialized constant Print) irb(main):002:0> require './print.rb' "print.rb" => true irb(main):003:0> Print => Print
require
により同じファイルが 2 度読み込まれることはありません。
これはグローバル変数$LOAD_PATH
(又は$"
、$-I
) に読み込んだファイルが保存され、読み込み済みかどうかを判定しているためです。
また、require
に指定されたファイルはグローバル変数$:
の配列に書かれた順に探索され、最初に見つかったファイルが読み込まれます。# require で読み込まれたファイルのパスはグローバル変数 $" に保存される irb(main):007:0> pp $".select {|p| p =~ %r{/print.rb\Z}} [] => [] irb(main):008:0> require './print.rb' "print.rb" => true irb(main):009:0> pp $".select {|p| p =~ %r{/print.rb\Z}} ["/<PATH_TO_CURRENT_DIRECTORY>/print.rb"] => ["/<PATH_TO_CURRENT_DIRECTORY>/print.rb"] # require に指定したファイル名はグローバル変数 $: で指定されたリストから順に探索される irb(main):002:0> pp $: ["/home/vagrant/.rbenv/rbenv.d/exec/gem-rehash", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/site_ruby/2.5.0", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/site_ruby/2.5.0/x86_64-linux", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/site_ruby", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/vendor_ruby/2.5.0", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/vendor_ruby/2.5.0/x86_64-linux", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/vendor_ruby", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/2.5.0", "/home/vagrant/.rbenv/versions/2.5.5/lib/ruby/2.5.0/x86_64-linux"] => ["/home/vagrant/.rbenv/rbenv.d/exec/gem-rehash", ...] # グローバル変数 $: にカレントディレクトリは無いため、ファイル名だけでは読み込めない irb(main):010:0> require 'print.rb' Traceback (most recent call last): 4: from /home/vagrant/.rbenv/versions/2.5.5/bin/irb:11:in `<main>' 3: from (irb):10 2: from /home/vagrant/.rbenv/versions/2.5.5/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' 1: from /home/vagrant/.rbenv/versions/2.5.5/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' LoadError (cannot load such file -- print.rb)一方で、
load
は何度実行してもファイルが読み込まれます。
またload
に指定したファイル名は拡張子.rb
や.so
が補完されず、読み込んだファイルのパスは$"
に追加されません。
require
メソッドはライブラリの読み込みに使われ、load
は設定ファイルの読み込みに使われることが想定されています。my_class.rbclass MyClass def self.hello p 'hello' end endirb(main):001:0> load './my_class.rb' => true irb(main):003:0> load './my_class.rb' => true irb(main):004:0> MyClass.hello "hello" => "hello" # ここで my_class.rb が更新された場合は load により変更が反映される # my_class.rb の更新内容は self.hello メソッドが返す文字列が "hello" -> "hello world" に変わったことです irb(main):006:0> load './my_class.rb' => true irb(main):007:0> MyClass.hello "hello world" => "hello world" # `load` により読み込んだファイルのパスは `$"` に追加されない $ irb irb(main):001:0> load './my_class.rb' => true irb(main):002:0> $".select {|p| p =~ /my_class.rb\Z/} => [] irb(main):003:0> require './my_class.rb' => true irb(main):004:0> $".select {|p| p =~ /my_class.rb\Z/} => ["/<PATH_TO_CURRENT_DIRECTORY>/my_class.rb"]このように
require
とload
メソッドを使うことで外部ファイルを読み込むことが出来ますが次のような違いがあります。
require
もload
もグローバル変数 `$:" に指定されたパスの配列から順に探索するrequire
はライブラリの読み込み、load
は設定ファイルの読み込みに使うよう想定されている
require
で指定したファイルは拡張子.rb
や.so
が補完されるlaod
で指定したファイルは拡張子は補完されないrequire
は同じファイルを 1 度だけ読み込む
- 既に読み込んだファイルはグローバル変数
$"
に保存されるload
は無条件に読み込む
- 読み込んだファイルはグローバル変数
$"
に保存されないRuby on Rails における話
bundle したファイルが require される仕組み
参考として、Rails が Bundler でインストールした gem を require せずに使えている仕組みを説明します。
app/config/application.rb
にその処理が書かれています。app/config/application.rbBundler.require(*Rails.groups)
Rails.groups
は RAILS_ENV により以下のように設定されます。# RAILS_ENV=development の場合 irb(main):009:0> Rails.groups => [:default, "development"] # RAILS_ENV=production の場合 irb(main):002:0> Rails.groups => [:default, "production"]尚、Gemfile に
require: false
が指定された場合は Bundler.require により require する対象から外れます。(参照)autoload の仕組み
Rails6 から自動読み込みの新しいモード
Zeitwerk
が追加されました。
ここでは Rails6 より前の Classic モードにおける自動読み込み(参照
)について説明します。autoload とは Ruby on Rails におけるソースコードに変更が加えられた時に自動読み込みする機能です。
例えば User モデルが
app/models/user.rb
で定義されている場合、require を指定せずに Rails アプリケーション内でUser
を呼び出すことが出来ます。$ bin/rails c # 未定義である状態で `User` モデルを使おうとすると、定義が自動で読み込まれて定義済となる irb(main):001:0> Object.constants.select{|p| p == :User} => [] irb(main):002:0> User.column_names => ["id", "name", "created_at", "updated_at"] irb(main):003:0> Object.constants.select{|p| p == :User} => [:User] # グローバル変数 $" にパスは追加されない irb(main):004:0> $".select{|p| p =~ /user.rb\Z/} => []この自動読み込みは development 環境ではデフォルト有効になっており、production 環境では無効化されています。(Rails5 でのデフォルト設定。Rails4 でのデフォルト設定は異なるようです。)
自動読み込みする対象となるファイルは
config.autoload_paths
に格納されています。
これはrequire
で使う$LOAD_PATH
とは異なる値が格納されています。デフォルトで
config.autoload_paths
に設定されているのは次のディレクトリです。(Rails5 でのデフォルト設定)
app
配下の第1ディレクトリapp/*/concerns
ディレクトリtest/mailer/previews
ディレクトリRails における自動読み込み処理の順序は次のとおりです。
尚、Rails における autoload ではクラスインスタンスやモジュールインスタンスは定数として取り扱います。
そのため以降の自動読み込みの説明においてもクラスインスタンスやモジュールインスタンスは定数として説明します。
(定数に対して autoload が働くため、クラスやモジュールではない一般的な定数も同じ仕組みで autoload されます)
- Ruby インタプリタにおける定数が未定義の場合に発生する const_missing をフックして Rails における自動読み込みをトリガーする
- ruby インタプリタは module, class キーワードの後ろに置かれる定数が未定義であれば定義を行う
- ruby インタプリタにより定義済と判定された定数は Rails の自動読み込みは行われない
- 呼び出し元のモジュール名を基準として、定数の名前を特定する
- 無名(
self.name == nil
)のモジュールで定義された定数の場合は、呼び出し元のモジュールは"Object"
となる- 定数が登場した箇所のネストに基づく名前となる
- 定数の名前からファイル名を特定する (定数とファイル名は
定数名.underscore == ファイル名
の関係)- ファイルが見つかった場合、
load
又はrequire
によりファイルが読み込まれる
ENV["NO_RELOAD"]
が指定されている場合はrequire
が使われ、それ以外はlaod
が使われる- ファイルが見つからないが、自動読み込み対象のモジュールである場合は該当する名前のモジュールを定義する
- 自動読み込み対象のモジュールは autoload_paths 配下にあるディレクトリを指す
- 例えば、
app/my_dir/my_class.rb
がある場合MyDir
という定数は自動読み込み対象のモジュールとして、Rails の自動読み込みによりモジュールとして定義される- ファイルが見つからず、自動読み込み対象のモジュールでもない場合は、親となるモジュールを基準として読み込み処理を繰り返す(上の2.から実行する)
参考: autoload は
AutoSupport::Dependencies
にてconst_missing
メソッドをオーバーライドすることで実装されています。
- ActiveSupport::Dependencies::ModuleConstMissing.const_missing
- ActiveSupport::Dependencies.load_missing_constant
例えばアプリケーションに
app/models/user.rb
が存在する場合に、コントローラ内で User を指定すると自動読み込みがどの順番で行われるか見ていきます。app/controllers/posts_controller.rbclass PostsController < ApplicationController def index @posts = User.current_user.posts end end上の例で定数
User
が自動読み込みされる場合を考えてみます。
すると、次の順序で自動読み込みが行われます。
- Ruby インタプリタは Object クラスインスタンスに User が存在しないとして
const_missing
を呼び出す- Rails が
const_missing
をフックして自動読み込みをトリガーする- 呼び出し元のモジュール名を基準として、定数の名前を特定する
- 定数が登場した箇所のネストに基づく名前となる
- →
PostsController::User
- 定数の名前からファイル名を特定する (定数とファイル名は
定数名.underscore == ファイル名
の関係)
- →
posts_controller/user.rb
を autoload_paths から探す- ファイルが見つからず、自動読み込み対象のモジュールでもない場合は、親となるモジュールを基準として読み込み処理を繰り返す
- →
::User
- 定数の名前からファイル名を特定する (定数とファイル名は
定数名.underscore == ファイル名
の関係)
- →
user.rb
を autoload_paths から探す- ファイルが見つかった場合、
load
又はrequire
によりファイルが読み込まれる
- →
app/models/user.rb
が見つかり load される以上が Rails における自動読み込みの仕組みです。
- Rails における自動読み込み(autoload)は
ActiveSupport::Dependencies
にて実装されている- autoload の対象となるファイルは
config.autoload_paths
から検索できるものである- ファイルは
load
により読み込まれる (require
は環境変数を指定した時に使われる)- ファイルではなくディレクトリであった場合は、自動読み込みモジュールとして定義される
- 定数が登場した箇所のネストに基づく名前を使った検索で見つからなかった場合は、親の名前空間を基準として検索が続けられる
更新されたファイルを再度読み込む仕組み
先に説明した autoload のアルゴリズムはあくまで未定義の定数を再読み込みする仕組みです。
Rails アプリケーションを開発していて RAILS_ENV=development でアプリケーションを動作させた時に、ファイルが更新されると自動で変更が反映されていることに気が付くと思います。
これは Rails アプリケーションのファイル更新をウォッチする
config.file_watcher
により、ファイルが更新されたことをトリガーとして、autoload されたファイル一覧が空に初期化され、定数の削除が行われることで実現します。つまり、定義済の状態を強制的に未定義の状態にすることで、次に定数が読み込まれるタイミングで autoload が実行されることが期待され、autoload により最新のファイルが読み込まれることで実現されています。
reload! の仕組み
reload! は定数の再読み込みを行うメソッドです。
development モードで動作する Rails アプリケーションは、ファイルが変更されるとクラスやモジュールを自動的に再読み込みします。(
config.cache_classes
が false なら自動読み込みが有効になり、config.cache_classes
が true なら自動読み込みが無効になる)しかし Rails console では逆に一貫した状態であることが望まれるため、
config.cache_classes
の値によらず再読み込みが行われません。そこで
reload!
メソッドを実行することで強制的に再読み込みすることが出来ます。これは Rails の内部で autoload されたファイル一覧が空に初期化され、また各クラスインスタンスに登録された定数が削除されるため強制的に再読み込みが出来ます。
注意点として既に変数にクラスインスタンスが代入されている場合、再読み込みが行われても変数内の状態は更新されません。
app/models/user.rbclass User < ApplicationRecord def self.num 1 end endirb(main):001:0> user = User => User (call 'User.connection' to establish a connection) irb(main):002:0> user.num => 1 # ここで、User.num が 2 を返すように修正する irb(main):003:0> reload! Reloading... => true # 既に変数に保存されたクラスインスタンスは変更されない irb(main):004:0> user.num => 1 # 新たに参照されたクラスインスタンスは変更される irb(main):005:0> User.num => 2
- 投稿日:2019-09-15T23:37:57+09:00
AWS secrets.ymlからcredentials.ymlへ
目次
- はじめに
- secrets.ymlとは?
- credentials.ymlとは?
- 具体的な変更
- 変更によって変わった手順
- 参考にしたwebサイト、書籍
- 参考になりそうなwebサイト、書籍
はじめに
私は、プログラミングをの勉強を初めてまだ2ヶ月の初心者であります。自分のアウトプットも兼ねてまだまだ技術は未熟ではありますが、私以外の初めて間もない方々の役に立つようなことができればと思いまして、投稿をさせていただきます。不備等ございましたら、恐れ入りますがコメントにてご指摘いただければ幸いでございます。
secrets.ymlとは?
Rails5.2より前のバージョンにおいて、秘匿情報(secret_key_baseや外部APIのアクセスキー等)を記述していたファイルのことです。このファイルにはデフォルトでアプリケーションのsecret_key_baseが含まれていました。
credentials.yml.encとは?
Rails5.2以降のバージョンにおいて用意された秘匿情報を保存しておくための新しいファイルです。Rails5.2からは暗号化されたcredentials.yml.encを扱います。しかし、secret.ymlも使うことはできるので、アップグレードの際にすぐに用意しなければならないというわけではありません。
また、credentials.yml.encの内容は暗号化されています。復号のやり方としては、master keyを利用して復号化することができます。デフォルトのmaster keyはconfig/master.keyを参照しましょう。編集の際は、rails credentials:editコマンドを使います。Rails5.2において生成される.gitignoreには、.config/master.keyが標準で含まれているので、gitリポジトリに誤って入れてしまうのを防ぐことができるようになっています。具体的な変更点
- config/credentials.yml.encを追加し、secrets.ymlの記述の際のように、各環境ごとに設定値をそれぞれ分ける仕様ではなくなった
- 開発やテストのシーン等、秘匿情報がの復号化の必要ない場面では求められなくなった 以上の2点が大きく変わった点かと思われます。
参考にしたwebサイト
AWS利用上のセキュリティを確保する方法
【Rails5.2】credentials.yml.encとmaster.keyでのデプロイによる今までとの変更点
Rails5.2から導入されたcredentials.yml.encを極める
Rails5.2から追加された credentials.yml.enc のキホン
Rails5.2からsecrets.yml*が廃止されcredentials.yml.encに統合されるよ
credentials.yml.encによるアクセスキーの管理方法
Rails セキュリティガイド
「Rails5.2」 credentials.yml.encを生成する方法
Railsのcredentials.yml.encは、どういった運用ができるか?
credentials.yml.encを環境ごとに使い分ける【Ruby on Rails】
Rails5.2 暗号化(Credentials)関連の単語メモ
Rails 5.2 の credentials.yml.enc に登録してあるデータを呼び出す方法
Rails の config/credentials.yml.enc を使ってみる
Rails5.2のcredential管理を試してみた
credentials.yml.enc やめたい…
Rails 4.1 の secret.yml とは…
Rails 5.2の本番デプロイ時に secrets.yml でハマった
secrets.ymlや環境変数をRails 5.2のEncrypted Credentialsに移行する
- 投稿日:2019-09-15T23:28:45+09:00
Ruby+Selenium+GlideでFNO(東京)を楽しむ術
まずはじめに
FNO前に投稿しようと思っていましたが、、、すいません
自己紹介
初投稿なので自己紹介します。
某ファッションテック企業でサーバーサイドエンジニアをしているものです。
普段は主にRuby書いていて、少しSwiftも触っています。この記事について
FNOはFASHION’S NIGHT OUT(https://www.vogue.co.jp/fno/2019/tokyo/#/about)のことで
毎年9月ごろにVOGUEが開催しているファッションイベントです。限定アイテムなどが発売されるなか
FNOの醍醐味といえば
ノベルティ ・ 酒
だと思っています。(個人的な意見になります)効率よくまわって楽しみたいなと思うのですが、
公式だと
地図を見るのに毎度ページ更新して確認して
というのがめんどくさいなと感じていました。そこで今回は
Seleniumu
を使用してスクレイピングをして
CSVを生成し、Glideで読み込みます!実装
準備&&環境
chromeをダウンロードしてください。
$ ruby -v ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin18]スクレイピング
selenium-webdriver
をインストールgem install selenium-webdriverchromeを開き、指定のURLに飛びます。
表示の時間を待ってから、スクロールする必要があります。(時間とスクロールは適当です)require 'selenium-webdriver' require 'csv' require 'pry' driver = Selenium::WebDriver.for :chrome driver.navigate.to 'https://www.vogue.co.jp/fno/2019/tokyo/shoplist/#/item/3' sleep(5) driver.execute_script('window.scroll(0,1000);') sleep(5) spots = driver.find_element(:id, 'cat_result').text.split(' ')[0].to_i必要なデータをCSVで抽出して行きます。
要素はxpathで取得しています。
xpathの取得方法に関しては下記を参考に。
https://qiita.com/ywindish/items/5a992c49387d81df900e今回各wrap内のリンク先に住所等が書いてあるため、
もう一つDriverでchromeを起動します。
同じDriverでも問題ないですが、
JavaScriptの関係で再度待機時間などが必要になることなどから
別でchromeを開いています。CSV.open('fno2019_tokyo.csv', 'w') do |csv| csv << %w[id name text image location link] driver.find_elements(:class, 'wrap').each.with_index(1) do |wrap, index| name = wrap.find_element(:xpath, "//*[@id='shopWrap']/li[#{index}]/a/div/div[2]/p[2]").text text = wrap.find_element(:xpath, "//*[@id='shopWrap']/li[#{index}]/a/div/div[2]/p[3]").text image = wrap.find_element(:xpath, "//*[@id='shopWrap']/li[#{index}]/a/div/div[1]/img").attribute('src') detail_link = wrap.find_element(:xpath, "//*[@id='shopWrap']/li[#{index}]/a").attribute('href') driver2 = Selenium::WebDriver.for :chrome driver2.navigate.to detail_link sleep(3) driver2.quit csv << %W[#{index} #{name} #{text} #{image} #{location} #{detail_link}] break if index == spots end endDriverを終了します。
driver.quitGlide
生成したCSVをGoogle Driveにアップロードして
Glide(https://go.glideapps.com/)を開き、
スプレッドシートで開きます。
先ほど生成したスプレッドシートを読み込むだけです。
あとは好みでデザインを変更できます。
参考
https://www.seleniumqref.com/api/webdriver_gyaku.html
https://morizyun.github.io/web/selenium-cheat-sheet.html最後に
下記が作成したものです。
https://x9kav.glideapp.io神戸、名古屋、大阪の開催も10月以降にありますので
参考にしていただければ幸いです。来年はドリンク、食事、それ以外のノベルティを
画像認識もしくは文字列判別で分類したいなと思っているところです。
- 投稿日:2019-09-15T23:17:53+09:00
【Rails】Turbolinksが原因でGoogle Analyticsが正常に動かない時の対処法
Ruby on RailsでWebアプリを作っていたら、Turbolinksでどハマりしてしまったのでメモ。
Google AnalyticsがTurbolinksの影響で正常に動かない場合の対処法を備忘録としてまとめてみました。
Rails5で作ったWebアプリのGoogle Analyticsが正常に動かない
力価計算.comという小児薬の服用量を計算するWebアプリを作ったのですが、Google Analyticsが正常に動いてないことに気づきました。
ページ遷移したときにGoogle AnalyticsのPVがカウントされない
Webアプリ上でページ遷移した時に、PVのカウントがされていない。
例えば、トップページから計算ページへに移動するとき、トップページのPVは測定できるのに計算ページのPVが測れていませんでした。
Google Analyticsが正常に動かなかった原因はTurbolinks
Google Analyticsが正常に動かなかった原因は、Turbolinksだったことが発覚。
Turbolinksはページの表示速度が早くなるというメリットがありますが、どうやらJavascriptの動きを邪魔してしまうことがあるらしい。
Google AnalyticsのコードはJavascriptで書かれているので、TurbolinksがGoogle Analyticsのコードの動きを邪魔してしまったようでした。
Turbolinksが原因でGoogle Analyticsが正常に動かない場合の対処法
解決法は、以下の通りです。
1:application.html.erbにGoogle Analyticsのコードを貼り付ける
まず以下のコードをapplication.html.erbにコピペ。
application.html.erb<% if Rails.env.production? %> <!-- Global site tag (gtag.js) - Google Analytics --> <script async src="https://www.googletagmanager.com/gtag/js?id=#{ENV['Your Google Analytics Tracking Code']}"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('Your Google Analytics Tracking Code'); </script> <% end %>2:application.jsにturbolinks対策のコードを貼り付け
次に、以下のコードをapplication.jsに貼り付けます。
Your Google Analytics Tracking Codeには、自分のトラッキングコード(UA-xxxxxxxx-xxx)を書いてください。
application.html.jsdocument.addEventListener('turbolinks:load', function(event){ if(typeof(gtag) == 'function'){ gtag('config', 'Your Google Analytics Tracking Code', { 'page_title' : event.target.title, 'page_path': event.data.url.replace(window.location.protocol + "//" + window.location.hostname, "") }); } })参照:https://github.com/turbolinks/turbolinks/issues/73
これで解決するはず。
ちなみに最初の行にあるturbolinks:load は、Turbolinksによってページが表示されるタイミングで発生するイベントです。
これでも動かなかった場合
実は僕の場合、これでも動かなかったのですが、rails assets:precompileのコマンドをターミナルで打ち込んだら正常に動くようになりました。
あと、最初はgoogle-analytics-railsというgemでGoogleアナリティクスを導入していたのですが、どうしても正常に動きませんでした。
なので、google-analytics-railsを使っていて、Google アナリティクスが動かない場合は、先ほど紹介したような感じで普通にGoogle Analyticsのトラッキングコードを貼り付けると良いと思います。
まとめ
Turbolinksは便利だけど厄介ですね。
少しずつ勉強していこうとと思います。
- 投稿日:2019-09-15T23:06:55+09:00
Railsチュートリアル2章
Gem
railsにはgemファイルというライブラリがある。
Gemfile内に使用したいgemを記述、開発環境用などグループ分けすることも可能らしい。
記述しただけでは意味がないのでインストールを行う。
$ bundle install --without productionbundleに記述した通りにインストールが実行される。
--without
を使うと上記だと
production(本番環境)のgemを除いたローカルgemがインストールされます。数が多かったりするとうまく動かない。(エラーになる)
その時は$ bundle updateを行う。
バリデーション
app/models/micropost.rbclass Micropost < ApplicationRecord validates :content, length: {maximum: 140} endバリデーションというのは
text入力内容や記述内容が要件を満たしているか、妥当性を確認すること
上記では
:content
、投稿する内容の
:length
長さが
{maximum: 140}
最大140文字
というバリデーションが記述されています。投稿する内容が140文字を越えるとエラーメッセージが表示されます。
他にもMVCなどについて詳しく書いてあるのですが
ほぼコピペになってしまいそうなので以上です。。。
- 投稿日:2019-09-15T22:44:21+09:00
Protocol Buffers / Ruby Generated Code(和訳)
このページは Protocol Buffers 公式リファレンス Ruby Generated Codeの和訳です。原文はCreative Commons Attribution 4.0 Licenseで公開されており、ソースコードはApache Licenseで公開されています。この訳文もそれにならいます。
Ruby Generated Code
このページでは、プロトコルバッファコンパイラが任意のプロトコル定義に対して生成するメッセージオブジェクトのAPIについて説明します。 このドキュメントを読む前に、proto3言語ガイドを読むことをお勧めします。
現時点ではまだproto3だけしかサポートされていません。proto2のサポートも計画されていますが、まだ利用できません1。
Rubyのプロトコルコンパイラはメッセージスキーマを定義するDSLからRubyのソースファイルを生成します。DSLは引き続き変更される可能性があります(特にproto2サポートなどの機能の追加時)が、 このガイドでは、DSLではなく生成されたメッセージのAPIのみを説明します。
コンパイラ呼び出し
プロトコルバッファコンパイラは
--ruby_out=
というコマンドラインフラグをつけて実行することでRubyのコードを生成します。--ruby_out=
オプションにはコンパイラにRubyコードを出力させたいディレクトリを直接指定します。コンパイラはそれぞれの.proto
ファイルの入力に対して、.rb
ファイルを作成します。出力ファイルの名前は.proto
ファイルの名前から取られますが、二点違いがあります。
- 拡張子 (
.proto
)は_pb.rb
で置き換えられます。- (
--proto_path=
か-I
のコマンドラインオプションで指定された)protoのパスは、(--ruby_out=
フラグで指定された)出力パスに置き換えられます。たとえば、次のようなコマンドを実行したとします。
protoc --proto_path=src --ruby_out=build/gen src/foo.proto src/bar/baz.protoコンパイラは
src/foo.proto
とsrc/bar/baz.proto
の入力から、build/gen/foo_pb.rb
とbuild/gen/bar/baz_pb.rb
の2つの出力ファイルを生成します。 コンパイラは必要に応じてディレクトリbuild/gen/bar
を自動的に作成しますが、buildまたはbuild/genは作成しません。それらはすでに作成済みである必要があります。パッケージ
.proto
ファイルで定義されたパッケージ名は生成されたメッセージ型のモジュール構造を生成するために使われます。このようなファイルがある場合、
package foo_bar.baz; message MyMessage {}プロトコルコンパイラは
FooBar::Baz::MyMessage
という名前のメッセージ型を出力します。メッセージ型
このようなシンプルなメッセージ宣言に対して、
message Foo {}プロトコルバッファコンパイラは
Foo
という名前のクラスを生成します。生成されたクラスはObject
クラスを継承しています(protoで共通の基底クラスはありません)。C++やJavaとは違って、Rubyが生成したコードは.proto
ファイルのoptimize_for
オプションの影響を受けません。実際のところ、Rubyコードの最適化対象は常にコードサイズとなっています
Foo
サブクラスを作成すべきではありません。生成されたクラスはサブクラス用に設計されていないため、「脆弱な基底クラス」の問題2を引き起こす可能性があります。Rubyのメッセージクラスは各フィールドに対するアクセサを定義します。また、次にあげる標準メソッドを提供します。
Message#dup
,Message#clone
: このメッセージのシャローコピーを行い、新しく作られたコピーを返します。Message#==
: 2つのメッセージの完全な等価比較を行います。Message#hash
: メッセージの値のシャローハッシュ値を計算します。Message#to_hash
,Message#to_h
: メッセージオブジェクトをRubyのHashオブジェクトに変換します。最上位のメッセージだけが変換されます。Message#inspect
: このメッセージを表す可読性のある表現の文字列を返します。Message#[]
,Message#[]=
: 文字列の名前でフィールドを取得または設定します。将来的には、これはおそらくget/set拡張にも使用されるでしょう。このメッセージクラスはまた次のような静的メソッドも定義します。(通常のメソッドだと.protoファイルで定義されるものと競合する可能性があるので、なるべく静的メソッドで実装するようにされています)
Message.decode(str)
: このメッセージのプロトコルバッファバイナリをデコードし、新しいインスタンスを返します。Message.encode(proto)
: このクラスのメッセージオブジェクトをバイナリ文字列にシリアライズします。Message.decode_json(str)
: このメッセージのJSON文字列をデコードして、新しいインスタンスとして返します。Message.encode_json(proto)
: このクラスのメッセージオブジェクトをJSON文字列にシリアライズします。Message.descriptor
: このメッセージオブジェクトのGoogle::Protobuf::Descriptor
を返します。このメッセージを作る場合、コンストラクタのフィールドで簡単に初期化できます。次にメッセージの作成と使用の例を示します。
message = MyMessage.new(:int_field => 1, :string_field => "String", :repeated_int_field => [1, 2, 3, 4, :submessage_field => SubMessage.new(:foo => 42)) serialized = MyMessage.encode(message) message2 = MyMessage.decode(serialized) raise unless message2.int_field == 1メッセージは別のメッセージの中にも宣言できます。 例:
message Foo { message Bar { } }
この場合、
Bar
クラスはFoo
クラスの中で宣言されるので、Foo::Bar
として参照できます。フィールド
メッセージ型の各フィールドには、フィールドに対してget/setするアクセサメソッドがあります。したがって、fooフィールドを指定すると、次のように記述できます。
message.foo = get_value() print message.fooフィールドを値を入れるたびに、そのフィールドで宣言された型に対して値が型チェックされます。 値の型が間違っている(または範囲外の)場合、例外が発生します。
単数フィールド (proto3)
単数のプリミティブなフィールド(数値、文字列、真偽値)の場合、セットする値はそのフィールドへの正しい型であるべきであり、適切な範囲内でなくてはなりません。
- 数値: 値は
Fixnum
、Bignum
もしくはFloat
であるべきです。 セットする値はそのフィールドで正確に表現できる型である必要があります。なのでint32
のフィールドに1.0
を入れても構いませんが、1.2は入れられません。- 真偽型フィールド: 値は
true
もしくはfalse
でなくてはなりません。 他の値の場合、暗黙的にtrue
/false
に変換されることはありません。- バイト配列フィールド: セットする値はStringオブジェクトである必要があります。 プロトコルバッファライブラリは文字列を複製し、ASCII-8BITエンコーディングに変換し、
freeze
します。- 文字列フィールド: セットする値はStringオブジェクトである必要があります。 プロトコルバッファライブラリは文字列を複製し、UTF8エンコーディングに変換し、
freeze
します。自動変換を実行してくれるようおな、自動の
#to_s
,#to_i
などの呼び出しはありません。もし必要であれば、自分で値を変換する必要がありますproto3は、単数非メッセージフィールドが明示的に設定されているかどうか、確認する方法を提供しないため、戻り値が0 / false / ""である場合は、その値がどこかで設定されたかデフォルト値のままということになります。
単数メッセージフィールド
フィールドの型がメッセージの場合、未設定であればフィールドは
nil
を返すため、メッセージが明示的に設定されたかどうかをいつでも確認できます。 値を明示的にnil
に設定して、そのフィールドをクリアすることもできます。if message.submessage_field.nil? puts "submessage フィールドは未設定です" else message.submessage_field = nil puts "submessageフィールドはクリアされました" endメッセージをセットするには、正しい型で生成されたメッセージオブジェクトである必要があります。
メッセージをセットする際に、メッセージを循環させることもできます。例です。
// foo.proto message RecursiveMessage { RecursiveMessage submessage = 1; } # test.rb require 'foo' message = RecursiveSubmessage.new message.submessage = messageもしこれをシリアライズすると、ライブラリは循環を検知して、シリアライズを失敗させます。
Repeatedフィールド
Repeatedフィールドは
Google::Protobuf::RepeatedField
のカスタムクラスを使って表現されます。このクラスはRubyのArray
のように振る舞い、Enumerable
モジュールをmix-inしています。通常のRuby配列とは異なり、RepeatedField
は特定の型から初期化され、配列のメンバーは全て正しい型でなくてはなりません。型と範囲はメッセージフィールドと同様にチェックされます。int_repeatedfield = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3]) # TypeErrorが発生 int_repeatedfield[2] = "not an int32" # RangeErrorが発生 int_repeatedfield[2] = 2**33 message.int32_repeated_field = int_repeatedfield # 許可されない。通常のRuby配列は型を強制できない message.int32_repeated_field = [1, 2, 3, 4] # これは通る。様子が安全な型の配列にコピーされるため message.int32_repeated_field += [1, 2, 3, 4]
RepeatedField
型は、通常のRuby配列と同じメソッドをすべてサポートしています。repeated_field.to_a
でいつものArrayクラスに変換できます。map フィールド
mapフィールドは、Rubyの
Hash
クラスのように動作する特別なクラス(Google::Protobuf::Map
)を使って表されます。 通常のHash
とは異なり、Map
は決まった型のキーと値で初期化され、Map
のすべてのキーと値は正しい型でなくてはなりません。 型と範囲は、メッセージクラスのフィールドやRepeatedField
の要素と同様にチェックされます。int_string_map = Google::Protobuf::Map.new(:int32, :string) # mapに要素がない場合、nilを返します print int_string_map[5] # 値は文字列でなければいけないのでTypeErrorが発生します int_string_map[11] = 200 # OK int_string_map[123] = "abc" message.int32_string_map_field = int_string_map列挙型
Rubyには組み込みの列挙型がないため、値を定義する定数を持つ各列挙型のモジュールを作成します。
次のような.protoファイルがある場合:
message Foo { enum SomeEnum { VALUE_A = 0; VALUE_B = 5; VALUE_C = 1234; } optional SomeEnum bar = 1; }次のように列挙型を参照できます。
print Foo::SomeEnum::VALUE_A # => 0 message.bar = Foo::SomeEnum::VALUE_A列挙型のフィールドには数字もしくはシンボルをセットすることができます。 値を読み戻すときに、列挙型の値が既知の場合はシンボルになり、未知の場合は数値になります。 proto3では列挙型が取りうる値の集合は制限されていないので、事前に定義されていなくても、列挙型フィールドに任意の数字を割り当てることができます。
message.bar = 0 puts message.bar.inspect # => :VALUE_A message.bar = :VALUE_B puts message.bar.inspect # => :VALUE_B message.bar = 999 puts message.bar.inspect # => 999 # RangeError: 列挙型フィールドに対する未知のシンボル message.bar = :UNDEFINED_VALUE # 列挙型の値でswitchさせるのが便利です case message.bar when :VALUE_A # ... when :VALUE_B # ... when :VALUE_C # ... else # ... end
Enum
モジュールは、次のユーティリティメソッドも定義します。
- Enum#lookup(number): 数値からラベルを探して返します。もし存在しなければnilを返します。数値に
- 相当するラベルが複数ある場合、最初に定義されたラベルを返します。
- Enum#resolve(symbol): ラベルから数値を返します。存在しない場合はnilを返します。
- Enum#descriptor: この列挙型のdescrptorを返します。
oneof
次のようなoneofを持ったメッセージ型があるとします。
message Foo { oneof test_oneof { string name = 1; int32 serial_number = 2; } }
Foo
に対応するRubyのクラスには、通常のフィールドと同じようなアクセサメソッドを持つname
とserial_number
というメンバー変数が含まれます。 ただし、通常のフィールドとは異なり、一度に1つまでしか、oneofのフィールドにには設定できません。そのため、あるフィールドに値を入れると他のフィールドはクリアされます。message = Foo.new # フィールドにはデフォルト値が入っている raise unless message.name == "" raise unless message.serial_number == 0 raise unless message.test_oneof == nil message.name = "Bender" raise unless message.name == "Bender" raise unless message.serial_number == 0 raise unless message.test_oneof == :name # serial_numberにセットするとnameがクリアされる message.serial_number = 2716057 raise unless message.name == "" raise unless message.test_oneof == :serial_number # serial_numberにnilを入れるとoneofフィールドがクリアされる message.serial_number = nil raise unless message.test_oneof == nil
- 投稿日:2019-09-15T22:17:28+09:00
Railsでチーム内共通の定数を利用する方法
Railsでチーム共通の定数を管理する
システムを作成していると、開発チームで共通の定数などを利用したいことがあると思います。
各画面共通の値やパラメーター等を共通で利用できれば、「あの画面では”1”の値が印刷済なのに、こっちの画面では”1”の値が印刷済み」になっているとかいう状態を防ぐことができます。
もちろん、DBから値を取ってくるということもできますが、「チリも積もれば山となる」極力DBへ負荷を避けるという利点もありますね:start:コンスト用のファイルを用意
config/initializer/constants.rbに次のようなファイルを用意します。
#constants.rb #サーバーサイドを通さず、クライアントサイド側で利用したい定数は別途jsファイルなどにまとめましょう module CommonConst ## クライアント名 CLIENT_NAME = "○○社総合人事システム" ## 業務区分 GYOMU_KBN = { "1" => "給与管理", "2" => "庶務事務管理", "3" => "勤怠管理" }.freeze end呼び出し方
例えば、viewファイルで次のように呼び出すことができます。
<nav class="navbar navbar-default"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbarEexample"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <!-- ↓ここ共通定数の呼び出し --> <a class="navbar-brand" href="/"><%= CommonConst::CLIENT_NAME %>総合人事システム</a> </div> <div class="collapse navbar-collapse" id="navbarEexample"> <ul class="nav navbar-nav"> <li class="active"><a href="#">メニューA</a></li> </ul> </div> </div> </nav>また、共通定数を利用した、セレクトボックスやラジオボタンの作成など、フォームコントロールを作成することもできます。
<h1 class="text-center">チームで決まったコンストを呼び出そう</h1> <div class="form-group"> <div> <%= label_tag '業務区分',nil,class:"label label-default" %> <%= select_tag('select_gyomu',options_for_select((CommonConst::GYOMU_KBN.invert),class:'option form-control',selected:"1"),include_blank:true)%> </div> </div>↓が呼び出し結果の画像です。
ナビゲーションバーの、
「○○社総合人事システム」と、「給与管理」という項目が出ているセレクトボックスが共通定数から利用しています。(値は適当です)このように、Railsでも結構簡単に、定数を利用できます。
(とはいえ、Rubyにおける定数は取り扱いを注意しないと、値を変えられたり、参照先を変えることができるので、注意が必要です)
- 投稿日:2019-09-15T21:38:15+09:00
Railsチュートリアル1章
railsチュートリアルを始めたので復習
$ rails serverローカル環境にサーバーが立ち上がる
$ rails _5.1.6_ new hello_apprailsのバージョン5.1.6に固定しhello_appを作成。
Git
$ git initgitのセットアップ。リポジトリの初期化。
rails new hello_app
したならhello_app
のルートディレクトリで行う。
hello_app
のファイルを入れる貯蔵庫を作りますよ〜的な感じ。$ git add -A現在のディレクトリにあるファイルが全てリポジトリに追加される。
貯蔵庫にファイルを入れますよ〜。$ git log #gitのログを表示 $ git status #gitのステータスを表示$ git commit -m "コメント"最後にコミットします。
-m
を使うとダブルクォーテーション内にコミットメッセージを
追加できます。-m
を使用しなければエディタが開いて入力する形になります。
add
で追加はしたけどリポジトリに反映がされていない状態?なのでcommit
が必要になります!リモートリポジトリの追加
$ git remote add 追加するリモートリポジトリ名 追加したいリポジトリ$ git remote add origin git@bitbucket.org:ユーザー名/hello_app.gitbitbucketの場合はbitbucket内でリポジトリを作成し、リポジトリのソースの上の方に
リポジトリが表記されているのでコピペして上記のようにできればOKです。$ git push -u origin --all最後に
push
を行うことでリモートリポジトリに追加されます!Heroku
$ Heroku createherokuのサーバーにアプリケーションの実行場所を作成します。
ここに作成したアプリケーションをpush
します。
この時生成されるアドレスをブラウザで開くことでデプロイしたアプリケーションを
表示できます。$ git push Heroku mastergitで
commit
されているリポジトリのmaster(ブランチ)をherokuにpush
します。
これでデプロイ完了です。HerokuではデータベースにSQLiteが使えないのでPostgreSQLを使用します。
なのでgemfileの書き換えなどで対処する必要があります。
開発環境(development)と本番環境(production)でgemの書き換えをします。第1章の内容を第5章終了時に復習を兼ねて記載しました。
認識が違う部分がまだまだあるとは思いますが何かあればコメントなどお願い致します!
- 投稿日:2019-09-15T18:07:35+09:00
Ruby on Rails 『NO FILEのマイグレーションファイルを削除する方法』
状態
$ rails db:migrate 実行後のマイグレーションファイルを削除してしまい、NO FILEのファイルが出来上がった。
解決方法
migrationの状態を確認。
$ rails db:migrate:status下記のように、migrationの一覧が表示されます。
upが$ rails db:migrate実行後。
downが$ rails db:migrate実行前。Status Migration ID Migration Name -------------------------------------------------- up 20190915023701 Create posts up 20190915065320 ********** NO FILE ********** down 20190915080932 Devise create usersMigration IDをコピペし、ダミーファイルを作成。(後で削除するので、hogeのところは適当でいいです。)
$ touch db/migrate/20190915065320_hoge.rb下記のように記述したダミーファイルを作っておく。
20190915065320_hoge.rbclass Hoge < ActiveRecord::Migration[6.0] def change end end$ rails db:migrate:status を実行してMigration Nameが付与されていることを確認。
Status Migration ID Migration Name -------------------------------------------------- up 20190915023701 Create posts up 20190915065320 Hog down 20190915080932 Devise create usersVERSION にMigration ID を代入して下コマンドを実行。
$ rails db:migrate:down VERSION=20190915065320これでdown(rails db:migrate実行前)になります。
Status Migration ID Migration Name -------------------------------------------------- up 20190915023701 Create posts down 20190915065320 Hoge down 20190915080932 Devise create users↓ 必要なくなったので削除。
$ rm db/migrate/db/migrate/20190915065320_hoge.rbあとは先程と同じく、$ rails db:migrate:status を実行すると消えてるのが確認できる。
Status Migration ID Migration Name -------------------------------------------------- up 20190915023701 Create posts down 20190915080932 Devise create users
以上がNO FILEのマイグレーションファイルを削除する方法でした。そもそも、つまらないミスをしなければこのような作業はしなくていいのですが...笑
参考資料
- 投稿日:2019-09-15T17:30:44+09:00
promptはrenderで消える
編集画面を作る際にpromptが消失した
MVCの流れで呼び出される時
renderで呼び出す時
実際のコード
.main__product__delivery__h2-choice = f.collection_select :delivery_method_id, @deliveryMethods, :id, :name, prompt: "---" = fa_icon "chevron-down", class: "main__product__delivery__sell-box__icon"どうやら仕様らしい…?
Select prompt option disappears when validation fails in Rails
https://stackoverflow.com/questions/4060737/select-prompt-option-disappears-when-validation-fails-in-rails
You can achieve the results you want by setting :include_blank to the string you were using for prompt.とのことなのでpromptからinclude_blankに書き換え
.main__product__delivery__h2-choice = f.collection_select :delivery_method_id, @deliveryMethods, :id, :name, include_blank: "---", = fa_icon "chevron-down", class: "main__product__delivery__sell-box__icon"
"---"自体は存在していることが確認できたのであとは"---"が初期値として選択されていればOK!最終的なコード
RubyonRails:collection_selectにデフォルト値を設定する
https://madogiwa0124.hatenablog.com/entry/2018/05/12/210801こちらのサイトを参考にして
.main__product__delivery__h2-choice = f.collection_select :delivery_method_id, @deliveryMethods, :id, :name, { include_blank: "---", selected:"" } = fa_icon "chevron-down", class: "main__product__delivery__sell-box__icon"結論
prompt: "---"を{ include_blank: "---", selected:"" }に書き換える!
- 投稿日:2019-09-15T17:00:11+09:00
AtCoder初参加者のためのPOINTメモ
この記事を書くまでの経緯
5日ぐらい前に「AtCoderはじめます!」と宣言したところ、とってもありがたいことにインターン先の社員さんやAtCodeをすでにやっている友達が「こんな事前準備をしといた方がいいよ!」とアドバイスしてくれました。
そこで、これからAtCoderをはじめる自分と同じ状況の方に向けて、もらったアドバイスの要点を書いていきたいと思います!
この記事で「これやってたら一瞬だったのにやってなかったばかりにめちゃめちゃ時間を使ってしまった(もしくは解けなかった)」ということがなるべくなくなるようにしたい所存です。
初参戦するまでにやっておくこと
標準入力・出力のやり方の確認
AtCoderで問題を解くときにおそらくすべての問題で使うのが標準入力と標準出力です。
しかし、わたしが標準入力・出力という言葉を始めて聞いたときは正直あまりピンとこないというのが素直な感想でした。
おそらく普段プログラミングをしているときにあまり使う機会はないのではないでしょうか。
そのため、時間を事前に確認しておかないとめちゃめちゃ時間をくってしまうので注意です。
ただ、言語によって多少コードの書き方が異なるので実際のやり方はqiitaの記事などで調べてみていただけたらと思います。
ちなみにRubyだと数字を一つ取得するとき(標準入力)の書き方はこんな感じです。
atcoder.rbnum = gets.to_iIf文やfor文の書き方の確認
また、if文・for文もAtCoderで問題を解く際によく使います。
これは普段の開発中にもよく使うのであまり問題はないかもしれませんが、本番中に「あれ?」とならないようにするためにも確認しておいた方がよいとのことでした。
ちなみに、ちょっとメタい話になってしまいますが、A・B問題ではfor文の重複はあまり問題視されないもののC問題からは扱うデータの量が大きくなるためfor文の重複をすると「処理に時間かかりすぎ!」言われることが多いそうです。
なのでfor文はできるたけ少なくしてコードを書いた方がよいらしいので頭の片隅に置いておきたいです。
過去問を解く
最後に、AtCoderのサイトで今までに出た問題が公開されているので自分の参加する言語で過去問を見ておくとよいとのことでした。
↓過去問が見れるページ
https://kenkoooo.com/atcoder/#/table/
過去問のページでは回答・解説はもちろん、他の人が実際に回答したものも見れるためそちらも参考にするとよいとのことでした。
また、過去問を解くのにこちらのQiitaの記事もおすすめとのこと。
https://qiita.com/drken/items/fd4e5e3630d0f5859067
まだざっとしか見れていませんが解説がめちゃめちゃ分かりやすいです。
ただ、回答の言語がC#?C+?(ちょっとどっちか忘れてしまいました)なので、それ以外で参加される方はコードの部分は参考程度に見て、解き方とやコメントの部分をしっかり読んで理解しておくとよいとのことです。
いざ出陣!Atcoderの問題を解くときにやること
問題を解くときは自分のローカルエディタで動作確認
Atcoderでは一度自分の回答を提出してしまうと、間違えていたときに結果が悪くなってしまうペナルティーがあるため、提出前にローカルエディタで確認しておくべし、とのことでした。
提出前に問題で与えられた入力例を全部確認!
また、エディタを使うのと同じ理由で問題で与えられた入力例はすべてチェックすべし!とのことでした。
特にAtCoderで一番簡単なA問題は1,2行で書けることもあるため、すべての入力例での動作確認するのが面倒くさくてそのまま提出したくなってしまいますが、しっかり確認していきたいです。
おまけ
もちろん個人のレベルにもよるのですが、インターン先の社員さんに「初参戦なら2問解けたら万々歳!」と言っていただけたので、まずは今日の初参戦で2問解ききることを目標に頑張りたいと思います!
それではお読みいただきありがとうございました!
- 投稿日:2019-09-15T15:07:05+09:00
bundle installとbundle updateの違い
はじめに
Railsチュートリアルを進めていく中で、両者のコマンドの違いがいまいち理解出来なかったので、備忘録として投稿します。
両者の違い
bundle install
ケース別によって動きが変わるため、以下図にまとめました。
bundle update
Gemfileを元にGemをインストールする。
各Gemのバージョンと依存関係にあるGemとバージョンが最新になる。
インストール後、Gemfile.lockを更新する。本番環境で
bundle update
は原則使用しない。
bundle update
を行うと各Gemとバージョンが最新化され、開発環境と同じ動作にならなくなる可能性があるため。用途
bundle install
新規開発スタート...必要なGemをインストールするため。
本番環境へデプロイ...開発環境と同じGemをインストールするため。bundle update
開発環境でGemを追加・更新...インストールするGem及び依存関係にあるGemを最新化させるため。参考記事
- 投稿日:2019-09-15T14:46:20+09:00
【Ruby】文字列をハッシュ化
関連
サンプルコード
# frozen_string_literal: true require 'digest' plain_text = 'password' puts 'MD5: ' + Digest::MD5.hexdigest(plain_text) puts 'RMD160: ' + Digest::RMD160.hexdigest(plain_text) puts 'SHA1: ' + Digest::SHA1.hexdigest(plain_text) puts 'SHA256: ' + Digest::SHA256.hexdigest(plain_text) puts 'SHA384: ' + Digest::SHA384.hexdigest(plain_text) puts 'SHA512: ' + Digest::SHA512.hexdigest(plain_text) # => MD5: 5f4dcc3b5aa765d61d8327deb882cf99 # RMD160: 2c08e8f5884750a7b99f6f2f342fc638db25ff31 # SHA1: 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8 # SHA256: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 # SHA284: a8b64babd0aca91a59bdbb7761b421d4f2bb38280d3a75ba0f21f2bebc45583d446c598660c94ce680c47d19c30783a7 # SHA512: b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86参考
- 投稿日:2019-09-15T14:08:13+09:00
【Ruby】AWS SSMパラメータストアの値を取得する
関連
準備
aws-sdk-ssm
をインストールする。下記コマンドを実行するか、
Gemfile
に追記する。
aws-sdk
をインストールしてもいいが、結構サイズが大きいので基本的には必要なものだけインストールするようにした方がいいと思う。gem install aws-sdk-ssm
or
gem 'aws-sdk-ssm'サンプルコード
今回はAWS SSM パラメータストアに以下のようなパラメータが作成してある。
パラメータ名 値 sample-parameter HOGEHOGE!! require 'aws-sdk-ssm' # 認証情報 # `~/.aws/credentials`に認証情報が設定されている場合、 # または環境変数`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`に認証情報が設定されている場合は # `access_key_id`と`secret_access_key`は不要 credentials = { access_key_id: 'xxxxxxxxxxxxxxxxxxxx', secret_access_key: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', region: 'ap-northeast-1' } # SSMクライアントを生成 ssm_client = Aws::SSM::Client.new(credentials) # リクエスト request = { name: 'sample-parameter', # パラメータ名 with_decryption: true # 暗号化されている場合は復号し、暗号化されていない場合は何もしない } response = ssm_client.get_parameter(request) pp response # => #<struct Aws::SSM::Types::GetParameterResult # parameter= # #<struct Aws::SSM::Types::Parameter # name="sample-parameter", # type="SecureString", # value="HOGEHOGE!!", # version=1, # selector=nil, # source_result=nil, # last_modified_date=2019-09-13 00:28:02 +0900, # arn="arn:aws:ssm:ap-northeast-1:xxxxxxxxxxxx:parameter/sample-parameter">> puts response.parameter.value # => HOGEHOGE!!参考
- 投稿日:2019-09-15T12:14:12+09:00
【Windows】RubyとRuby on Raisの環境構築でSQLite3まわりで苦労した
はじめに
結論から言うと、Ruby,Rails,SQLite3の各どのバージョンをダウンロードすればいいのかわからずエラー出しまくりだったので、参考までに残します。
実際にYay! You’re on Rails!がでたバージョン
(もっと良いバージョンがあるかもしれません)環境
OS: Windows10 64bit
Ruby version: 2.4.7 (x64-mingw32)
Rails version: 5.2.3
SQLite3 version: 1.3.6エラー内容
rails のインストールをし、rails new でプロジェクトを作成し、「rails s」を流したところエラーが出たのでGemfileの9行目くらいを
Gemfile# Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.3.6'に変えてインストールし直せば、エラーが解消されました。
どうやらデフォルトで入るSQLite3がRuby 2.4.7に対応していないようです。
Q&Aサイトに似たようなところで苦労されている方がいたので少しでも力になれば幸いです。参考サイト
https://knkomko.hatenablog.com/entry/2019/02/23/110443
http://mashiroyuya.hatenablog.com/entry/windows10RoR
- 投稿日:2019-09-15T11:24:47+09:00
`rails new` せずに小さなRailsアプリを作成
Railsアプリを作る際は最初に
rails new
を実行する。すると大量のファイルが作られ、その中には様々な設定が最初から書かれている。はっきり言ってどれが何をしているのかよく分からない。そこで
rails new
せずに、サーバー実行時のエラーを見ながら少しずつファイルや設定を加えてみた。 "Hello, world!\n" の14バイトのテキストを返すだけのアプリができるまでをまとめる。
- Gitリポジトリ
- 参考資料
TL;DR
必要なファイルまとめ
一般的なパス パスの定義元 書くべき処理 bin/rails
railties/lib/rails/app_loader.rb
定数 APP_PATH
を定義した後、rails/commands
を読み込むconfig/application.rb
ユーザー定義定数 APP_PATH
Rails::Application
を継承したクラスを定義するconfig.ru
rails server --config=XXX
Railsアプリを初期化、実行する
(今回はルーティングも書いた)app/controllers/xxx_controller.rb
ルーティング・自動読み込み リクエストに応じて処理する 今回のアプリでは、上記ファイルは合計で20行しかない。
$ git ls-files | xargs wc -l 5 .gitignore 7 Gemfile 135 Gemfile.lock 5 app/controllers/mini_controller.rb 3 bin/rails 8 config.ru 4 config/application.rb 167 total前準備
Windows Subsystem for Linux上のUbuntu 16.04で試している。
Rubyのバージョン選択
既にrbenvが入っているとする。新しくRuby 2.6.4が出ていたのでインストールする。あまり他に影響を与えたくないので、バージョン指定はこのシェルでのみ有効なようにする。
(cd $(rbenv root)/plugins/ruby-build/ && git pull) rbenv install --skip-existing 2.6.4 rbenv shell 2.6.4Gitリポジトリの作成
適宜保存するために作成しておく。
mkdir -p ~/projects/rails_mini_app cd ~/projects/rails_mini_app git init git commit --allow-empty # 一応、空っぽの時点で保存しておくRailsのインストール
bundle init sed --in-place --expression='s/^# *gem/gem/' Gemfileこれで、gem
rails
をインストールするGemfileが完成する。(2019/09/14時点の最新版は6.0.0)Gemfile# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "rails"不要になったら跡形もなく消せるよう、gemは作業ディレクトリ内にインストールする。git管理は不要なので
.gitignore
で除外しておく。bundle install --path=vendor/bundle cat << EOF >> .gitignore /.bundle /vendor EOFRailsアプリ作成
初期状態で確認
早速railsサーバーを起動してみる。
bundle exec rails server
Usage: rails new APP_PATH [options] Options: ... Example: rails new ~/Code/Ruby/weblog This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
rails new
のヘルプが表示された。暗にこれを実行しろと言われている。
bin/rails
の作成と、定数APP_PATH
の定義ヘルプからでは必要なファイルがわからないので、「Railsの初期化プロセス」を読む。gem以外で最初のファイルは
bin/rails
であるらしい。1.2
railties/lib/rails/app_loader.rb
exec_app
の主な目的は、Railsアプリケーションにあるbin/rails
を実行することです。カレントディレクトリにbin/rails
がない場合、bin/rails
が見つかるまでディレクトリを上に向って探索します。これにより、Railsアプリケーション内のどのディレクトリからでもrails
コマンドを実行できるようになります。ただし試したところ、適当なコードだと
rails new
のヘルプが表示されるままだった。ヘルプを回避するにはAPP_PATH
という文字列を含める必要があった。(定数かどうかはここでは関係ない)bin/rails#!/usr/bin/env ruby # APP_PATHこの状態でサーバーを起動すると、ヘルプは表示されなくなるが他のことも起きない。
rails/commands
の読み込みと、APP_PATH
の指すファイル準備サーバー起動処理(railsコマンドの実行)へ進むには、
rails/commands
を読み込ませる必要がある。また、その中で定数APP_PATH
のファイルも読み込まれるので、一般的なパスであるconfig/application.rb
をとりあえず空ファイルで作っておく。bin/rails#!/usr/bin/env ruby APP_PATH = File.expand_path('../config/application', __dir__) require 'rails/commands'これでサーバーを起動するとNoMethodErrorが発生する。
/home/user/projects/rails_mini_app/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:142:in `block in perform': undefined method `root' for nil:NilClass (NoMethodError)railties-6.0.0/lib/rails/commands/server/server_command.rb#L133-152def perform extract_environment_option_from_argument set_application_directory! prepare_restart Rails::Server.new(server_options).tap do |server| # Require application after server sets environment to propagate # the --environment option. require APP_PATH Dir.chdir(Rails.application.root) # ここでエラー if server.serveable? print_boot_information(server.server, server.served_url) after_stop_callback = -> { say "Exiting" unless options[:daemon] } server.start(after_stop_callback) else say rack_server_suggestion(using) end end endRailsアプリの用意
Rails.application
が無いのが問題らしい。config/application.rb
の中にRailsアプリを書く。config/application.rbclass MiniApp < Rails::Application endこれでサーバーを起動すると、親切に次の作業のヒントを出してくれる。
=> Booting WEBrick => Rails 6.0.0 application starting in development http://localhost:3000 => Run `rails server --help` for more startup options configuration config.ru not found Exitingなお、設定ファイルは
--config
オプションで指定できるので、config.ru
でなくてもいい。
config.ru
の用意空ファイルを用意するだけだと、サーバー起動時にエラーになる。
=> Booting WEBrick => Rails 6.0.0 application starting in development http://localhost:3000 => Run `rails server --help` for more startup options Exiting Traceback (most recent call last): ... 1: from config.ru:2:in `<main>' /home/user/projects/rails_mini_app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:146:in `to_app': missing run or map statement (RuntimeError)
run
が必要らしいので、実際のアプリに存在する1行を加える。config.rurun Rails.applicationこれでサーバーを起動すると、またNoMethodErrorが発生する。
=> Booting WEBrick => Rails 6.0.0 application starting in development http://localhost:3000 => Run `rails server --help` for more startup options Exiting Traceback (most recent call last): ... /home/user/projects/rails_mini_app/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:80:in `log_to_stdout': undefined method `formatter' for nil:NilClass (NoMethodError)railties-6.0.0/lib/rails/commands/server/server_command.rb#L76-86def log_to_stdout wrapped_app # touch the app so the logger is set up console = ActiveSupport::Logger.new(STDOUT) console.formatter = Rails.logger.formatter # ここでエラー console.level = Rails.logger.level unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT) Rails.logger.extend(ActiveSupport::Logger.broadcast(console)) end endRailsアプリの初期化
loggerといえばいつも
config/environments/<env>.rb
で何か設定している覚えがある。今回はconfig.ru
でrequire_relative 'config/environment'
をしていないため、抜けている処理がそこにあると考えられる。探したら怪しい1行があったので、直接config.ru
に加える。config.ruRails.application.initialize! run Rails.applicationこれでついにサーバーが起動する。
log/
とtmp/
が作られるので、.gitignore
で除外しておくといい。=> Booting WEBrick => Rails 6.0.0 application starting in development http://localhost:3000 => Run `rails server --help` for more startup options config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly: * development - set it to false * test - set it to false (unless you use a tool that preloads your test environment) * production - set it to true [%Y-%m-%d %H:%M:%S] INFO WEBrick 1.4.2 [%Y-%m-%d %H:%M:%S] INFO ruby 2.6.4 (2019-08-28) [x86_64-linux] [%Y-%m-%d %H:%M:%S] INFO WEBrick::HTTPServer#start: pid=XXXXX port=3000しかしクライアントからアクセスすると500エラーになる。
[%Y-%m-%d %H:%M:%S] ERROR NameError: uninitialized constant ActionController::Base /home/user/projects/rails_mini_app/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.0/lib/action_dispatch/middleware/static.rb:78:in `ext' ... 127.0.0.1 - - [%d/%b/%Y:%H:%M:%S %Z] "GET / HTTP/1.1" 500 325 - -> /Rails関連のgemの読み込み
普通のアプリと比較して抜けている処理のうち、
ActionController
が読み込まれなさそうなものは、railsのgemの読み込みと考えられる。今回は機能が非常に少ないのでrails/all
ではなくaction_controller/railtie
のみを読み込む。config/application.rbrequire 'action_controller/railtie' class MiniApp < Rails::Application endこれでサーバーを起動してクライアントからリクエストすると、(当然ではあるが)RoutingErrorになる。
Started GET "/" for 127.0.0.1 at %Y-%m-%d %H:%M:%S %z ActionController::RoutingError (No route matches [GET] "/"): ... 127.0.0.1 - - [%d/%b/%Y:%H:%M:%S %Z] "GET / HTTP/1.1" 404 0 - -> /ルーティングとcontrollerを定義
普通は
config/routes.rb
に書くが、ファイルを作らず他の場所に書けないか試した。その結果、Railsアプリ初期化後なら設定が反映された。config.ruRails.application.initialize! Rails.application.routes.draw do root to: 'mini#index', via: :all match '*any', to: 'mini#index', via: :all end run Rails.applicationもちろんcontrollerが無いとエラーになるので、ルーティングに対応するものを作成しておく。
app/
直下は自動読み込みの探索対象なので、ディレクトリ名はcontrollers
でなくても構わない。app/controllers/mini_controller.rbclass MiniController < ActionController::Base def index render plain: "Hello, world!\n" end endこれでついにサーバーが 200 OK を返す。
Started GET "/" for 127.0.0.1 at %Y-%m-%d %H:%M:%S %z Processing by MiniController#index as */* Rendering text template Rendered text template (Duration: 0.1ms | Allocations: 3) Completed 200 OK in 308ms (Views: 307.8ms | Allocations: 1269) 127.0.0.1 - - [%d/%b/%Y:%H:%M:%S %Z] "GET / HTTP/1.1" 200 14 - -> /
ルーティングをRails初期化前に書くと無効なようで、development環境ではRailsのwelcome画面が表示された。
Started GET "/" for 127.0.0.1 at %Y-%m-%d %H:%M:%S %z Processing by Rails::WelcomeController#index as */* Rendering vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/templates/rails/welcome/index.html.erb Rendered vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/templates/rails/welcome/index.html.erb (Duration: 129.8ms | Allocations: 415) Completed 200 OK in 183ms (Views: 154.5ms | Allocations: 2171) 127.0.0.1 - - [%d/%b/%Y:%H:%M:%S %Z] "GET / HTTP/1.1" 200 399720 - -> /これらのルーティングはこっそり加えられている。
railties-6.0.0/lib/rails/application/finisher.rb#L74-86initializer :add_builtin_route do |app| if Rails.env.development? app.routes.prepend do get "/rails/info/properties" => "rails/info#properties", internal: true get "/rails/info/routes" => "rails/info#routes", internal: true get "/rails/info" => "rails/info#index", internal: true end app.routes.append do get "/" => "rails/welcome#index", internal: true end end endその他
動作しないこと
- Rakeタスク全般
- No Rakefile found (looking for: rakefile, Rakefile, rakefile.rb, Rakefile.rb)
bin/rails
による実行
- cannot load such file -- rails/commands (LoadError)
bundle exec
を省くための設定が必要
- 普通は
config/boot.rb
に記載して読み込み- ルーティング確認(
bundle exec rails routes
)
config/routes.rb
を直接参照するためGemの削減
gem
rails
はaction*
やactive*
などに依存しているが、そのほとんどは今回使用していない。エラーに出てきたのはrailties
なので、それに差し替える。Gemfile# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "railties"これでgemが43個から24個に減った。
- 投稿日:2019-09-15T11:14:15+09:00
[学習確認用] Ruby 配列の中からランダムな値を一つ抜き取る
配列の中からランダムな値を一つ抜き出す。
number = [1, 3, 4, 5, 11, 12] nunber_count = number.count puts number_count 1.times do puts number[rand(number_count)] endnumber_count の所は数字でもいけるが配列の数より大きい値を入れると空の値を抜き出してしまうから今回は配列の数をランダムの数に入れている。
- 投稿日:2019-09-15T11:08:00+09:00
#Ruby で 処理速度を平均化したい。sleep で必ず一定時間以上かかる処理を作る。
処理にかかった時間を得て、最低時間に満たなかったら足りない分を sleep させる
例
def some_action # some action end start_time = Time.now.to_f some_action done_time = Time.now.to_f under_time = 0.1 diff_time = under_time - (done_time - start_time) sleep diff_time if diff_time.positive? }ベンチマークの例
require 'benchmark' [*1..10].map { Benchmark.realtime { start_time = Time.now.to_f; sleep rand(0.01..0.10); done_time = Time.now.to_f; under_time = 0.1; diff_time = under_time - (done_time - start_time); sleep diff_time if diff_time.positive?; } } # => [0.10333599988371134, 0.10502699995413423, 0.10417600022628903, 0.10169599996879697, 0.1034500002861023, 0.10172299994155765, 0.10186100006103516, 0.10312700038775802, 0.10354600008577108, 0.10065300017595291]Original by Github issue
- 投稿日:2019-09-15T10:43:17+09:00
S3に保存した画像を表示する(Rails)
概要
例えば、あるサービスで画像をアップロードする際にS3を使うことはよくあるだろう。
そのS3にアップロードした画像を表示させたいということは結構あるのでは?(私がそれをやりたい)
私がやりたいのは以下の条件である。
- S3はパブリックアクセスをオフ
- 通常S3にアクセスできるのは特定のプログラムからのみ
この条件で、サービスからのみ画像を表示するようにする方法を書きます。
実行環境
Ruby 2.6.3
AWS S3手順
S3について
前述した通り、パブリックアクセスはオフにしておきます。
ポリシーはこれぐらいしか書いてません。
S3policy{ "Version": "2012-10-17", "Id": "Policyxxxxxxxxxxx", "Statement": [ { "Sid": "Stmtxxxxxxxxxxx", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::xxxxxxxxxxxx:user/your_name" }, "Action": [ "s3:DeleteObject", "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::your_bucket_name/*" } ] }S3の特定のオブジェクトにアクセスしようとすると以下の画面のようにAccessDeniedになります。
これを回避するために一時的に閲覧可能となる期限付きURLというものがあります。
期限付きURLについて
期限付きURLとは、文字通り一時的に閲覧可能となるURLで、指定した時間を経過すると閲覧できなくなるものです。
これを利用して、サービス利用者のみS3に保存された画像を閲覧できるようにします。ここではRubyでのやり方を示しますが、他の言語でもAWSのSDKがあればできるはずです。
AWS S3 SDKのインストール
Gemfileを使った方法を書きますが、使わない方はgemでインストールしてください。
Gemfileに以下を書いてインストールします。Gemfilegem 'aws-sdk-s3'期限付きURLの発行
以下の例ではプログラムからのみアクセスできるようにS3を設定しているのでCredentialを指定しています。
表示時間は60秒として設定しました。s3 = Aws::S3::Resource.new( region: REGION_NAME, # 1. 利用しているリージョン credentials: Aws::Credentials.new( AWS_ACCESS_KEY, # 2. プログラムからアクセスできるユーザのアクセスキー AWS_SECRET_ACCESS_KEY # 3. プログラムからアクセスできるユーザのシークレットキー ) ) signer = Aws::S3::Presigner.new(client: s3.client) presigned_url = signer.presigned_url(:get_object, bucket: bucket_name, key: key, expires_in: 60)Presigner.presigned_urlで期限付きURLを発行しています。
生成されたURLにアクセスすると閲覧できるはずです。HTMLで画面に表示する場合には通常通りimgタグのsrcにこの期限付きURLを入れれば良いだけです。
以上
- 投稿日:2019-09-15T03:05:38+09:00
[devise_token_auth]ヘルパーメソッドが使えない(undefined)ときの対処法
公式のドキュメントをちゃんと読めばわかる内容ですが、地味にはまったので書きます…発生したエラー
ログインしたユーザーのみアクセス可能にしたpostsコントローラにリクエストを送ったところ以下のようなエラーが出ました。
NoMethodError (undefined method `authenticate_user!' for #<Api::V1::PostsController:0x00007f0a5806dee8>):解決策
どうやらdevise_token_authのヘルパーメソッドを記述するときはroute.rbの内容次第で変更しなければならないようです。
僕のルートはroutes.jsRails.application.routes.draw do devise_for :users namespace :api do namespace :v1 do mount_devise_token_auth_for 'User', at: 'auth', controllers: { registrations: 'api/v1/auth/registrations' } resources :posts end end # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html endという感じになっています。
namespace
が使われているので/api/v1/auth
とのようになります。
この時、ヘルパーメソッドを以下の様に変更しなくてはなりません
before after before_action :authenticate_user! before_action :authenticate_api_v1_user! current_user current_api_v1_user まとめ
英語のドキュメントばかりで大変でしたが、この記事が日本の駆け出しエンジニアの助けになれば幸いです!
twitterやってるのでよければフォローしてください!
ID: @extreammoney
- 投稿日:2019-09-15T00:20:30+09:00
Herokuにデプロイをする時に詰まった箇所について
はじめに
RailsアプリケーションをHerokuにデプロイする際、自分が詰まった箇所について説明します。
また、herokuへのデプロイ方法は、最終行に記載した<4.デプロイ手順の参考記事>を参考にデプロイをしました。それぞれのバージョンは以下の通りです。
MacOS 10.14.5
Ruby 2.5.1p57
Rails 5.2.3
heroku/7.26.2 darwin-x64 node-v11.14.0画像
https://gyazo.com/847aa4661ae3b2f278ae2328d33d32dd1.Herokuにログインする時
①現象
以下のように、herokuにログインするコマンドを実行しても、
$heroku loginメールアドレスおよびパスワードを入力する画面いならない(おそらく、このような方法でログインすることもできるのだろう)。
動画(見えづらくて申し訳ありません(>人<;))
https://gyazo.com/e3873154a60890c7fa5aab07146c962c②解決方法
以下のようなコマンドを入力すれば、解決できます。
$ heroku login --interactive動画
https://gyazo.com/4829936b6a6626a7ea229383eecbeae9③参考記事
https://teratail.com/questions/158638
2.Railsの設定
(1).Gemfileの設定
本番環境用にGemfileの設定しておかないと、以下のようなエラーが発生します。
(今回は、自分がアプリで使用したdeviseおよびjquery-railsの2つのgemを例にあげます。)①エラー現象
以下のような画面が表示され、デプロイが失敗する。
deviseの場合、
remote: Caused by: remote: NameError: uninitialized constant Devise画像
https://gyazo.com/eb6608754ad0937c550eb45acdf848b5jquery-railsの場合、
remote: rake aborted! remote: Sprockets::FileNotFound: couldn't find file 'jquery' with type 'application/javascript'画像
https://gyazo.com/71cc267fe306d82fdf6e65df2b2288a1②解決方法
Gemfileの一番下に、以下のような設定をすると解決します(deviseおよびjquery-rails)。
group :development, :production, :test do gem 'devise' gem 'jquery-rails' end画像
https://gyazo.com/625adb044cecaff749c60f4f77fb317a(2).テンプレートリテラル記法を用いる場合のproduction.rbの設定
①エラー現象
以下のようなエラー画面が表示され、デプロイが失敗する。
remote: rake aborted! remote: Uglifier::Error: Unexpected character '`'下の方に赤文字で以下のような表示がされる。
remote: ! Precompiling assets failed.全体の画像
https://gyazo.com/37b8b091eda6cec2c0514b54dea5a5c5②解決方法
config/environments/production.rbにある以下のコードをコメントアウトする。
# config.assets.js_compressor = :uglifier自分の場合、production.rbの26行目に書いてありました。
https://gyazo.com/b66d6c1a13d7b22a5105f88e1303f40dそもそも、テンプレートリテラル記法とは?
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/template_strings3.デプロイ成功後
(1).デプロイは成功後にアクセスするURLについて
①現象
herokuへのデプロイが成功すると、以下のような長いログの画面が表示される
https://gyazo.com/2d2e4ea40e66373aa6b62cb7df7f15cc
(画面が青い理由は、どこからどこまでがデプロイのログなのかを、自分で判断するためです。見えづらくて申し訳ありません(>人<;))。そして、以下のような画面が表示される。
$ git push heroku master ・ ・ ・ remote: -----> Compressing... remote: Done: 36.9M remote: -----> Launching... remote: Released v6 remote: https://enigmatic-reaches-21915.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/enigmatic-reaches-21915.git * [new branch] master -> masterそして、同時にherokuへのURLが生成されます。
remote: Released v6 remote: https://enigmatic-reaches-21915.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/enigmatic-reaches-21915.git * [new branch] master -> master②解決方法
アクセスできるURLは以下のような表示がされている方にアクセスすると解決します。
remote: https://<個別のアプリの名前>.herokuapp.com/ deployed to Heroku※自分は、今回デプロイするときのアプリの名前を指定してなかったので、
enigmatic-reaches-21915という名前になっています。
③参考記事
https://qiita.com/kodai_0122/items/a1f01b18bb3e0ddde62a
(2).デプロイは成功し、正しいURLにアクセスしたが、エラー画面が表示される問題
①エラー現象
正しいURLにアクセスした時、以下のようなエラー画面が表示される。
"We're sorry, but something went wrong."画像
https://gyazo.com/3a6a0c733d87efe0866c2e3f8d585a0f②解決方法
デプロイをした後に、本番環境においてマイグレーションを行えば、解決できます。
③参考記事
https://i.gyazo.com/3a6a0c733d87efe0866c2e3f8d585a0f.png
https://qiita.com/KazuhoE/items/06d13ccd4c72fd31c5d9
https://teratail.com/questions/1241834.デプロイ手順の参考記事
・https://qiita.com/NaokiIshimura/items/eee473675d624a17310f
・https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39
・https://sweets-engineer.com/heroku/#heroku
・https://qiita.com/fuwamaki/items/f7752eb7a2727660239f