- 投稿日: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: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: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-15T21:12:40+09:00
#Rails + shoryuken gem で Worker を起動するときは --rails フラグをつけるべし? ActiveJob の perform が実行されなくてハマった。 Workerは動いているのに。
--rails
フラグをつけて worker を起動したら、ついに処理されるようになった。bundle exec shoryuken --config config/shoryuken.yml --railsHelp
shoryuken --help shoryuken [options] -c, --concurrency INT Processor threads to use -d, --daemon Daemonize process -q, --queue QUEUE[,WEIGHT]... Queues to process with optional weights -r, --require [PATH|DIR] Location of the worker -C, --config PATH Path to YAML config file -R, --rails Attempts to load the containing Rails project -L, --logfile PATH Path to writable logfile -P, --pidfile PATH Path to pidfile -v, --verbose Print more verbose output -V, --version Print version and exit -h, --help Show helphttps://www.rubydoc.info/github/phstc/shoryuken
shoryuken.yml
aws: access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %> secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %> region: us-east-1 concurrency: 1 queues: - example1 - example2 - example3shoryuken_worker.rb
class ShoryukenWorker include Shoryuken::Worker shoryuken_options queue: 'example1', auto_delete: true shoryuken_options queue: 'example2', auto_delete: true shoryuken_options queue: 'example3', auto_delete: true def perform(sqs_msg, name) puts "Hello, #{name}" end endinitializers/shoryuken.rb
Shoryuken.configure_server do |config| # Replace Rails logger so messages are logged wherever Shoryuken is logging # Note: this entire block is only run by the processor, so we don't overwrite # the logger when the app is running as usual. Rails.logger = Shoryuken::Logging.logger Rails.logger.level = :info # config.server_middleware do |chain| # chain.add Shoryuken::MyMiddleware # end # For dynamically adding queues prefixed by Rails.env # Shoryuken.add_group('default', 25) # %w(queue1 queue2).each do |name| # Shoryuken.add_queue("#{Rails.env}_#{name}", 1, 'default') # end end # config/initializers/shoryuken.rb Shoryuken.active_job_queue_name_prefixing = trueconfig/application.rb
require_relative 'boot' require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module RailsActiveJobExample class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.0 config.active_job.queue_adapter = ENV['QUEUE_ADAPTER'].present? ? ENV['QUEUE_ADAPTER'].to_sym : :sidekiq # config.active_job.queue_adapter = :shoryuken # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end endmake job
QUEUE_ADAPTER=shoryuken bundle exec rails runner 'ShoryukenJob.perform_later("ABC")'Original by Github issue
- 投稿日: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-15T15:57:53+09:00
【Rails】ActionMailer開発時にLetterOpnerWebが非常に便利だった。
はじめに
RailsでActionMailer実装時にお試しでletter_opner_webと言うのを使ってみました。
非常に手軽で便利だったので、使い方などの整理と振り返り用のメモです。
※Rails標準にも「MailerPreview」と言う機能があるみたいなのですが、テスト利用を想定して作られたものみたいだったので、こちらのgemを使うことにしました。間違えている所などあれば、ご指摘・指南いただければ嬉しいです。
(未解決課題なんかもあり、、、)Letter_opner_web
擬似的にメールの受信や閲覧ができる便利なgemです。
GitHubはコチラ前提:開発環境での利用に特化
※テスト環境でも行けそうな気はするけど、それこそ「MailerPreview」か(・ω・)デモのご紹介
letter_opner_webはデモサイトが用意されています。
実装前にどんなものか気になる方は触ってみてください。デモサイト:http://letter-opener-web.herokuapp.com/
【 利用手順 】
①受信・閲覧のためのメール送信からスタート
下記画面で[Email]と[Message]を入力して[Send mail]をクリック!
※Emailは存在しないものでも問題ありません
②画面下部に成功メッセージを確認
下図のようなメッセージが出ていれば、送信に成功しています。
③letter_opner_web画面を開く
デモ画面の"Click here to see sent mails"のリンクをクリックすれば、letter_opner_webで実際に見れる画面が表示されます!
なお、EmailアドレスごとにメッセージBOXが存在するわけではなく、送信した全てのEmailアドレスのメール内容がここから確認できます。
(本番で使ったらセキュリティリスク高めな感じですね笑)
④テストメッセージ削除
確認が完了したら、念のため画面左上の[Clear]ボタンでメール削除しておきましょう。
こんな感じで、開発時にメールサーバなどを用意するのが手間だなと思ったら、まずはletter_opner_webでお試ししてみるのも良いかと^^
ありえないEmail宛のメッセージでも許容してくれるので、手軽さが増します。設定方法(開発環境)
以下、letter_opner_webの設定方法をザクっとご説明。
Gemfile追加
gemファイルに設定を追加して
bundle install
を実行してください。group :development do gem ' letter_opener_web '、'〜> 1.0 ' end設定ファイル追加
開発環境の環境設定ファイルにメーラの設定を追加します。
config/environments/development.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 } ActionMailer::Base.delivery_method = :letter_openerルーティング設定
画面を持っているものなので、ルーティングの設定が必要になります。
下記のように設定追加してください。config/routes.rbRails.application.routes.draw do # 足すのは↓の行だけです! mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? endこれでletter_opner_webの設定は終わり!
超簡単!あとは下記のアドレスにアクセス知れば確認ができます!!letter_opner_web: http://localhost:3000/letter_opener
↓ 実際に開いてみるとこんな感じ ↓
動作確認
設定はできたものの出来ればメールが飛ぶか見てみたいですよね。
と言う事で、サクッとメールも飛ばしてみましょう。ActionMailer作成
コンソールから、controller作るときと同じ要領でActionMailer作ります。
※公式ドキュメントには”SampleMailer”のように指定するように記述がありますが”Mailer"部分はジェネレートする際に勝手に付与されます。知らずにやるとSampleMailerMailerみたいに残念なフォルダやクラスが作成されるので注意です笑$ rails g mailer Sample Running via Spring preloader in process 15548 create app/mailers/sample_mailer.rb invoke haml create app/views/sample_mailer invoke test_unit create test/mailers/sample_mailer_test.rb create test/mailers/previews/sample_mailer_preview.rbなお、controllerと同じく
rails d mailer Sample
で削除も可能です。ActionMailerを編集する
①共通部
Application_mailers.rbは、ActionMailer全体で適用されます。
初期状態で以下のように送信元メールアドレスとメールフォームが設定されています。
もし、送信元メールアドレスを変更したいのであれば、下記のdefault from:
を編集してください。
※各Mailerで個別に送信元を編集することもできるようですapp/mailers/application_mailers.rbclass ApplicationMailer < ActionMailer::Base default from: 'from@example.com' # 送信元メールアドレス layout 'mailer' # メール全体に適用されるメールフォーム(Viewsのapplication.html.hamlなどと共通の原理かと) end②SampleActionMailer
ここで送信メソッドを定義します。メソッド名は自由に決めちゃって良いかと思います。
今回メソッド内で設定するのはメールヘッダ部分のみです。
(body部も書けますが、管理が煩雑になるので基本的には切り出すようです)app/mailers/sample_mailer.rbclass SampleMailer < ApplicationMailer attr_accessor :email,:title,:name def sample_mail(email,title,name) #仮引数に@付きのインスタンス変数は指定できませんので注意 @email = email #インスタンス変数に格納 @title = title #インスタンス変数に格納 @name = name #インスタンス変数に格納 mail to: @email, #メールの宛先を指定 subject: "【テストメール】#{@title}" #メールのタイトルを指定 end end※モデルを使用していないため、無理やり項目作っていますが、普通は@userとかかと。
メールフォーム(body部)を編集する
メールのbody部は、Viewsフォルダ配下に作成します。
rails g
コマンドで実行した時点で、該当のActionMailerに対応するフォルダが、Viewsフォルダ配下に作成されています。このフォルダ配下にActionMailerで作成したメソッドと同名のファイルを作成し、body部を記述します。記述方法は、基本的にviews作成時と同じ感じです。
(プレーンテキストとhtmlで切り替えできそうですが、htmlのみを対象としています。)app/views/sample_mailer/sample_mail.html.haml= "#{@name}さん" %br %p Hello World!!設定自体はこれで完了です。
controllerなどからActionMailerを呼び出せばOK。
この部分ちょっと端折って、コンソールから検証してみます。
※今回端折りますが下図[4]のようにcontrollerなどに記載すればメール送信可能になりますコンソール.railsc#引数を下準備 [1] pry(main)> email = "test@gmail.ccooom" => "test@gmail.ccooom" [2] pry(main)> title = "Hello World" => "Hello World" [3] pry(main)> name = "はむすけ" => "はむすけ" #ActionMailerを実行してみる(最後に”.deliver”付けないと送信されません!!!) [4] pry(main)> SampleMailer.sample_mail(email,title,name).deliver実行結果を見ると、どう言う順で読み込まれてるか、何となくイメージが湧きますね。
この結果、下記の画面が開きます。コンソール.実行結果Rendering sample_mailer/sample_mail.html.haml within layouts/mailer Rendered sample_mailer/sample_mail.html.haml within layouts/mailer (9.2ms) SampleMailer#sample_mail: processed outbound mail in 5075.2ms Sent mail to test@gmail.ccooom (37.0ms) Date: Sun, 15 Sep 2019 14:23:42 +0900 From: from@example.com To: test@gmail.ccooom Message-ID: <5d7dcade41695_3f143fbfadc14e5c744d@user-nameMacBook-Air.local.mail> Subject: =?UTF-8?Q?=E3=80=90=E3=83=86=E3=82=B9=E3=83=88=E3=83=A1=E3=83=BC=E3=83=AB=E3=80=91Hello?= =?UTF-8?Q?_World?= Mime-Version: 1.0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <!DOCTYPE html>=0D <html>=0D <head>=0D <meta content=3D'text/html; charset=3Dutf-8' http-equiv=3D'Content-Type'>= =0D <style>=0D /* Email styles need to be inline */=0D </style>=0D </head>=0D <body>=0D =E3=81=AF=E3=82=80=E3=81=99=E3=81=91=E3=81=95=E3=82=93=0D <br>=0D <p>=0D Hello World!!=0D </p>=0D =0D </body>=0D </html>=0D => #<Mail::Message:70092500977860, Multipart: false, Headers: <Date: Sun, 15 Sep 2019 14:23:42 +0900>, <From: from@example.com>, <To: test@gmail.ccooom>, <Message-ID: <5d7dcade41695_3f143fbfadc14e5c744d@user-nameMacBook-Air.local.mail>>, <Subject: 【テストメール】Hello World>, <Mime-Version: 1.0>, <Content-Type: text/html>, <Content-Transfer-Encoding: quoted-printable>>
成功はしているみたいですが、rails s
してないからletter_opner_web自体は開けません(:_;)
と言うことで、rails s
してから、適当なところでbinding.pryしてみましょう(あくまで面倒臭がる)この状態でletter_opner_webにアクセスしてみましょう。今度はアクセスできるはず。コンソール.binding.pry5: def index => 6: binding.pry [1] pry(#<PostsController>)> email = "test@gmail.ccooom" => "test@gmail.ccooom" [2] pry(#<PostsController>)> title = "Hello World" => "Hello World" [3] pry(#<PostsController>)> name = "はむすけ" => "はむすけ" [4] pry(#<PostsController>)> SampleMailer.sample_mail(email,title,name).deliver
補足(課題込み)
letter_opner_webはプロジェクト単位でメールデータを保持しているようです。
上の図でrails c
で試したメールも残っていることから、サーバ起動、停止などを繰り返しても消えることは無いようです。プロジェクトフォルダが肥大化しないよう注意が必要かなと思いました。ちなみに送信メールの保存場所は「tmp/letter_opner/」配下です。
(デフォルトでgitignore対象となっています)
もし、保存場所を変えたい場合は、initilizerにletter_opner_web用のファイルを作成し、そこで定義すればOKみたいです。config/initializers/letter_opner_web.rbLetterOpenerWeb.configure do |config| config.letters_location = Rails.root.join('public', 'email') # 上記パスの中身"#<Pathname:/Users/user-name/projects/miniblog/public/mail>" end※当方うまく設定できてません。試したところ、こうなります。
<それぞれの挙動>
メールデータ格納先
→デフォルトの「tmp/letter_opner」のまま。フォルダ消しても蘇ってきます笑
letter_opner_web参照先
→設定が効いているのか、何も見えなくなる笑…畜生め(TωT)!!!
と思いつつ、configの設定がうまくいっていないのか・・・?!
と思いrails s
した時点で、configの設定状況を確認してみる(↓)。
うん、想定通りに読み込まれてる。指定のパスもcdで行ける。(思考停止)console.[1] pry(#<PostsController>)> LetterOpenerWeb.config.letters_location => #<Pathname:/Users/user-name/projects/miniblog/public/mail> [2] pry(#<PostsController>)> LetterOpenerWeb.config => #<LetterOpenerWeb::Config:0x00007fb9d9ee2948 @letters_location=#<Pathname:/Users/user-name/projects/miniblog/public/mail>>ここに時間を割き過ぎるのもなので、一旦ここまで。
もう少しinitilizerとかconfigとか、理解が進めば思い返してみることもあるかも。。。まとめ
手軽にメール機能を試せるのは、いいな〜と感じました。
ただ、色々試していると基礎知識がまだまだ足りないな〜と思い知らされます^^;
今後も、より深くrubyやrailsを知っていけるように頑張ります。。参考
GitHub:letter_opner_web
Rails公式ガイド:Action Mailer の基礎
開発中にrailsから送信したメールを確認する
- 投稿日:2019-09-15T15:57:53+09:00
【Rails】ActionMailer実装時にLetterOpnerWebが非常に便利だった。
はじめに
RailsでActionMailer実装時にお試しでletter_opner_webと言うのを使ってみました。
非常に手軽で便利だったので、使い方などの整理と振り返り用のメモです。
※Rails標準にも「MailerPreview」と言う機能があるみたいなのですが、テスト利用を想定して作られたものみたいだったので、こちらのgemを使うことにしました。間違えている所などあれば、ご指摘・指南いただければ嬉しいです。
(未解決課題なんかもあり、、、)Letter_opner_web
擬似的にメールの受信や閲覧ができる便利なgemです。
GitHubはコチラ前提:開発環境での利用に特化
※テスト環境でも行けそうな気はするけど、それこそ「MailerPreview」か(・ω・)デモのご紹介
letter_opner_webはデモサイトが用意されています。
実装前にどんなものか気になる方は触ってみてください。デモサイト:http://letter-opener-web.herokuapp.com/
【 利用手順 】
①受信・閲覧のためのメール送信からスタート
下記画面で[Email]と[Message]を入力して[Send mail]をクリック!
※Emailは存在しないものでも問題ありません
②画面下部に成功メッセージを確認
下図のようなメッセージが出ていれば、送信に成功しています。
③letter_opner_web画面を開く
デモ画面の"Click here to see sent mails"のリンクをクリックすれば、letter_opner_webで実際に見れる画面が表示されます!
なお、EmailアドレスごとにメッセージBOXが存在するわけではなく、送信した全てのEmailアドレスのメール内容がここから確認できます。
(本番で使ったらセキュリティリスク高めな感じですね笑)
④テストメッセージ削除
確認が完了したら、念のため画面左上の[Clear]ボタンでメール削除しておきましょう。
こんな感じで、開発時にメールサーバなどを用意するのが手間だなと思ったら、まずはletter_opner_webでお試ししてみるのも良いかと^^
ありえないEmail宛のメッセージでも許容してくれるので、手軽さが増します。設定方法(開発環境)
以下、letter_opner_webの設定方法をザクっとご説明。
Gemfile追加
gemファイルに設定を追加して
bundle install
を実行してください。group :development do gem ' letter_opener_web '、'〜> 1.0 ' end設定ファイル追加
開発環境の環境設定ファイルにメーラの設定を追加します。
config/environments/development.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 } ActionMailer::Base.delivery_method = :letter_openerルーティング設定
画面を持っているものなので、ルーティングの設定が必要になります。
下記のように設定追加してください。config/routes.rbRails.application.routes.draw do # 足すのは↓の行だけです! mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? endこれでletter_opner_webの設定は終わり!
超簡単!あとは下記のアドレスにアクセス知れば確認ができます!!letter_opner_web: http://localhost:3000/letter_opener
↓ 実際に開いてみるとこんな感じ ↓
動作確認
設定はできたものの出来ればメールが飛ぶか見てみたいですよね。
と言う事で、サクッとメールも飛ばしてみましょう。ActionMailer作成
コンソールから、controller作るときと同じ要領でActionMailer作ります。
※公式ドキュメントには”SampleMailer”のように指定するように記述がありますが”Mailer"部分はジェネレートする際に勝手に付与されます。知らずにやるとSampleMailerMailerみたいに残念なフォルダやクラスが作成されるので注意です笑$ rails g mailer Sample Running via Spring preloader in process 15548 create app/mailers/sample_mailer.rb invoke haml create app/views/sample_mailer invoke test_unit create test/mailers/sample_mailer_test.rb create test/mailers/previews/sample_mailer_preview.rbなお、controllerと同じく
rails d mailer Sample
で削除も可能です。ActionMailerを編集する
①共通部
Application_mailers.rbは、ActionMailer全体で適用されます。
初期状態で以下のように送信元メールアドレスとメールフォームが設定されています。
もし、送信元メールアドレスを変更したいのであれば、下記のdefault from:
を編集してください。
※各Mailerで個別に送信元を編集することもできるようですapp/mailers/application_mailers.rbclass ApplicationMailer < ActionMailer::Base default from: 'from@example.com' # 送信元メールアドレス layout 'mailer' # メール全体に適用されるメールフォーム(Viewsのapplication.html.hamlなどと共通の原理かと) end②SampleActionMailer
ここで送信メソッドを定義します。メソッド名は自由に決めちゃって良いかと思います。
今回メソッド内で設定するのはメールヘッダ部分のみです。
(body部も書けますが、管理が煩雑になるので基本的には切り出すようです)app/mailers/sample_mailer.rbclass SampleMailer < ApplicationMailer attr_accessor :email,:title,:name def sample_mail(email,title,name) #仮引数に@付きのインスタンス変数は指定できませんので注意 @email = email #インスタンス変数に格納 @title = title #インスタンス変数に格納 @name = name #インスタンス変数に格納 mail to: @email, #メールの宛先を指定 subject: "【テストメール】#{@title}" #メールのタイトルを指定 end end※モデルを使用していないため、無理やり項目作っていますが、普通は@userとかかと。
メールフォーム(body部)を編集する
メールのbody部は、Viewsフォルダ配下に作成します。
rails g
コマンドで実行した時点で、該当のActionMailerに対応するフォルダが、Viewsフォルダ配下に作成されています。このフォルダ配下にActionMailerで作成したメソッドと同名のファイルを作成し、body部を記述します。記述方法は、基本的にviews作成時と同じ感じです。
(プレーンテキストとhtmlで切り替えできそうですが、htmlのみを対象としています。)app/views/sample_mailer/sample_mail.html.haml= "#{@name}さん" %br %p Hello World!!設定自体はこれで完了です。
controllerなどからActionMailerを呼び出せばOK。
この部分ちょっと端折って、コンソールから検証してみます。
※今回端折りますが下図[4]のようにcontrollerなどに記載すればメール送信可能になりますコンソール.railsc#引数を下準備 [1] pry(main)> email = "test@gmail.ccooom" => "test@gmail.ccooom" [2] pry(main)> title = "Hello World" => "Hello World" [3] pry(main)> name = "はむすけ" => "はむすけ" #ActionMailerを実行してみる(最後に”.deliver”付けないと送信されません!!!) [4] pry(main)> SampleMailer.sample_mail(email,title,name).deliver実行結果を見ると、どう言う順で読み込まれてるか、何となくイメージが湧きますね。
この結果、下記の画面が開きます。コンソール.実行結果Rendering sample_mailer/sample_mail.html.haml within layouts/mailer Rendered sample_mailer/sample_mail.html.haml within layouts/mailer (9.2ms) SampleMailer#sample_mail: processed outbound mail in 5075.2ms Sent mail to test@gmail.ccooom (37.0ms) Date: Sun, 15 Sep 2019 14:23:42 +0900 From: from@example.com To: test@gmail.ccooom Message-ID: <5d7dcade41695_3f143fbfadc14e5c744d@user-nameMacBook-Air.local.mail> Subject: =?UTF-8?Q?=E3=80=90=E3=83=86=E3=82=B9=E3=83=88=E3=83=A1=E3=83=BC=E3=83=AB=E3=80=91Hello?= =?UTF-8?Q?_World?= Mime-Version: 1.0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <!DOCTYPE html>=0D <html>=0D <head>=0D <meta content=3D'text/html; charset=3Dutf-8' http-equiv=3D'Content-Type'>= =0D <style>=0D /* Email styles need to be inline */=0D </style>=0D </head>=0D <body>=0D =E3=81=AF=E3=82=80=E3=81=99=E3=81=91=E3=81=95=E3=82=93=0D <br>=0D <p>=0D Hello World!!=0D </p>=0D =0D </body>=0D </html>=0D => #<Mail::Message:70092500977860, Multipart: false, Headers: <Date: Sun, 15 Sep 2019 14:23:42 +0900>, <From: from@example.com>, <To: test@gmail.ccooom>, <Message-ID: <5d7dcade41695_3f143fbfadc14e5c744d@user-nameMacBook-Air.local.mail>>, <Subject: 【テストメール】Hello World>, <Mime-Version: 1.0>, <Content-Type: text/html>, <Content-Transfer-Encoding: quoted-printable>>
成功はしているみたいですが、rails s
してないからletter_opner_web自体は開けません(:_;)
と言うことで、rails s
してから、適当なところでbinding.pryしてみましょう(あくまで面倒臭がる)この状態でletter_opner_webにアクセスしてみましょう。今度はアクセスできるはず。コンソール.binding.pry5: def index => 6: binding.pry [1] pry(#<PostsController>)> email = "test@gmail.ccooom" => "test@gmail.ccooom" [2] pry(#<PostsController>)> title = "Hello World" => "Hello World" [3] pry(#<PostsController>)> name = "はむすけ" => "はむすけ" [4] pry(#<PostsController>)> SampleMailer.sample_mail(email,title,name).deliver
補足(課題込み)
letter_opner_webはプロジェクト単位でメールデータを保持しているようです。
上の図でrails c
で試したメールも残っていることから、サーバ起動、停止などを繰り返しても消えることは無いようです。プロジェクトフォルダが肥大化しないよう注意が必要かなと思いました。ちなみに送信メールの保存場所は「tmp/letter_opner/」配下です。
(デフォルトでgitignore対象となっています)
もし、保存場所を変えたい場合は、initilizerにletter_opner_web用のファイルを作成し、そこで定義すればOKみたいです。config/initializers/letter_opner_web.rbLetterOpenerWeb.configure do |config| config.letters_location = Rails.root.join('public', 'email') # 上記パスの中身"#<Pathname:/Users/user-name/projects/miniblog/public/mail>" end※当方うまく設定できてません。試したところ、こうなります。
<それぞれの挙動>
メールデータ格納先
→デフォルトの「tmp/letter_opner」のまま。フォルダ消しても蘇ってきます笑
letter_opner_web参照先
→設定が効いているのか、何も見えなくなる笑…畜生め(TωT)!!!
と思いつつ、configの設定がうまくいっていないのか・・・?!
と思いrails s
した時点で、configの設定状況を確認してみる(↓)。
うん、想定通りに読み込まれてる。指定のパスもcdで行ける。(思考停止)console.[1] pry(#<PostsController>)> LetterOpenerWeb.config.letters_location => #<Pathname:/Users/user-name/projects/miniblog/public/mail> [2] pry(#<PostsController>)> LetterOpenerWeb.config => #<LetterOpenerWeb::Config:0x00007fb9d9ee2948 @letters_location=#<Pathname:/Users/user-name/projects/miniblog/public/mail>>ここに時間を割き過ぎるのもなので、一旦ここまで。
もう少しinitilizerとかconfigとか、理解が進めば思い返してみることもあるかも。。。まとめ
手軽にメール機能を試せるのは、いいな〜と感じました。
ただ、色々試していると基礎知識がまだまだ足りないな〜と思い知らされます^^;
今後も、より深くrubyやrailsを知っていけるように頑張ります。。参考
GitHub:letter_opner_web
Rails公式ガイド:Action Mailer の基礎
開発中にrailsから送信したメールを確認する
- 投稿日:2019-09-15T15:49:45+09:00
Gemfile.lockを削除する時はエディタで表示して、ターミナルからrmするのが楽。
Gemfile.lockを削除してみましょう。
Railsの環境構築系で調べていると
こういう記事を見かけることがある。
わざわざコピペするのもgitで戻すのも面倒。テキストエディタ
私はsublime textやVSCodeを使っていますが、
そちらでGemfile.lockを開く、
ターミナルからコマンドで削除。という風にすると未保存のファイルとしてエディタには残り、
環境としてはGemfile.lockが消えている動作になる。
元に戻す時はcommand+sですぐに戻るので便利ですね。最後に
使っている機能が何によるモノなのか?
分解して考えられるととても便利に開発出来るなあと
最近強く感じております。
- 投稿日:2019-09-15T15:23:53+09:00
rails popular error of top 10
Topic about top 10 error
tell us popular error and
way to prevent them1.ActionController::RoutingError
this error get 404error
this means your app doesn't have URL.
2. NoMethodError: undefined method '[]' for nil:NilClass
- avoid user&
street = user&.address&.street3.ActionController::InvalidAuthenticityToken
CSRF (Cross Site Request Forgery)
word
- gotchas 落とし穴
relevant
- ex) errors are not relevant to most readers.
dig in
- see detail
classic
- very typical of its kind.
errant 間違った
- errant users
keep in mind
ex)
You should also keep in mind that
- notation 表記方法
- retrieve
internal error 内部エラー
vulnerability 脆弱性
malicious 悪意のある
mitigate 半減させる
記事
https://dev.to/philnash/top-10-errors-from-1000-ruby-on-rails-projects-and-how-to-avoid-them-24m
- 投稿日: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-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-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-15T01:51:14+09:00
Sass(SCSS)で使用出来る@mixinについて
始めに
作成した個人アプリをリファクタリングする際Sassの機能の一つ@mixinを使用したのでその使用方法について説明します。
@mixin
(ミックスイン)とは?定義したスタイルを別のスタイルに
@include
を使用して何度も呼び出す事が可能になるというものです。
よく使うスタイルを@mixin
で定義しておけばどこからでも@include
を使用すれば呼び出せるので、コードが見易くなり、メンテナンスもしやすくなります。記述方法
先ずは基本的な使用方法から
@mixin
の後にクラス名を定義して使用します。
その後使用したいファイルに@include
を使用して定義します。mixin.scss@mixin white { color: white; font-size: 2rem; }test.scss.test{ @include white; float: left; } 実際の中身 .test { color: white; font-size: 2rem; float: left; }後はパーシャルファイルを読み込むのを忘れないよう
@import
をファイル内に記述します。application.scss@import "modules/mixin"; @import "test";引数を使用した方法
引数を使用した方法の場合ha
$引数名
を()内に定義して使用します。mixin.scss@mixin centerwhite($size) { color: white; text-align: center; font-size: $size; }この様に定義する事で今回の場合はサイズ指定をする事が出来るようになります。
使用方法はクラス名の後の()の中に指定します。test.scss.test { @include centerwhite(2rem); float: left; } 実際の中身 .test { color: white; text-align: center; font-size: 2rem; float: left; }2つ以上の引数の場合
()内に複数
$引数名
を使用する事で複数指定する事も可能になります。mixin.scss@mixin colorstyle($color,$size) { color: $color; font-size: $size; }test.scss.test { @include colorstyle(white,2rem); float: left; } 実際の中身 .test { color: white; font-size: 2rem; float: left; }この様に複数指定すれば、色やサイズなどの指定が容易に出来、メンテナンスもしやすくなる為、便利だと思います。
最後に
以上基本的な
@mixin
の使用方法でした。この他にも色々応用的な使用方法もありますので、今後使いこなせる様になれたらと思います。
以下、参考にさせて頂いた資料です。
https://www.webcreatorbox.com/tech/sass-mixin
- 投稿日:2019-09-15T01:06:50+09:00
[Rails]ajaxでpostアクションを叩いたらsessionが拾えなかった。
どうもこんばんは、Rails学習2〜3ヶ月くらいのChihaです。
タイトル通り、jQueryからajaxでアクションを叩いて動かすと、それまで定義してきたsessionの値が拾えなくなる現象に遭遇&解決したので、ざっくりと書きます。開発環境
- Ruby on Rails 5.2.2
- Ruby 2.5.1
- jQuery
概要
ajaxからのpostリクエストを叩くと、アプリ側に持たせていたsessionの値が取得できなくなった。
signup.js//何かしらの処理後 $.ajax({ url: "/signup", type: "POST",//コントローラのアクションをpostで叩く data: { //送るデータとか }, async: false //今回は同期通信でした })signup_controller.rb(例)#前のページでの入力項目をsession保存 def before_page_content session[:birthyear] = profile_params[:birthyear] session[:birthmonth] = profile_params[:birthmonth] session[:birthday] = profile_params[:birthday] end #ajaxで叩くcreateアクション #/signup(method: :post) def create ※下のcreateが失敗する @profile = Profile.create( birthyear: session[:birthyear], birthmonth: session[:birthmonth], birthday: session[:birthday] ) endこんな感じのコードでjsから直接postメソッドのアクションを叩くと、それまでに取得して来ることができたはずのsessionの値が全部nilになっていた。そりゃ当然失敗する。
ターミナルActionController::InvalidAuthenticityTokenエラーはこういうのが出ました。
解決策
signup.js//何かしらの処理後 $.ajax({ url: "/signup", type: "POST", data: { //送るデータとか }, //下の記述を追記 beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')); },//ここまで async: false })これで無事にcreateアクションでsessionの値を拾って処理ができるようになりました。
Rails not reloading session on ajax post
【Rails API】ActionController::InvalidAuthenticityTokenの解決方法
外部からPOSTできない?RailsのCSRF対策をまとめてみた解決はこの辺りを参考にしました。
どうやら、RailsでのCSRF対策にjsからget以外のメソッドを叩いたのが悪かったようです。
【Rails API】ActionController::InvalidAuthenticityTokenの解決方法
詳しい理由とCSRFについてはこの記事に書かれてます。トラブルの経緯
スクールでの開発にて、wizard形式(複数ページに渡りユーザー情報を入力させ、最後のページで一括createする形式)でのユーザー登録機能を実装していた時の話。
各ページで入力された値は、sessionとしてアプリ側に預ける形に(詳しくはそのうち)。
最終ページでクレジットの情報を登録する必要があったため、payjpを利用することに。payjpでは、ユーザーが入力したクレジット情報をjavascript経由でpayjpに送り、トークンの情報を返す処理を行うことで、クレジット情報をRails側で使用せず、トークンを用いたユーザーのクレジットカード登録機能の実装、使用が可能となります。
こちらについては詳しくはpayjp.jsのリファレンス(カード情報のトークン化)で。というわけで、最終ページでcreateではなく、payjp.jsでのトークン取得を経てcreateする形で実装することに。
つまり、jsでの処理を経由してpayjpからのトークンを取得したのち、トークンをjsから投げつつ、postメソッドのcreateアクションを叩く、という感じでの実装を考えた。
ここでjsからcreateアクションを叩くとsessionが一つも取得できなくなっていた。
要するに上記の症状が発生していた。
↓
js側に記述を書き足すと解決した。という流れになります。
かなりアバウトな感じになりましたが、詳しくは上記の参考記事にて。
クレジットカード登録を含めたwizard形式でのユーザー登録フォームの実装については、長くなりそうなので後日ということで。。。最後に
引き続き気まぐれにトラブルや知った技術などを忘備録として書いていこうと思います。
まだまだ右も左もあやふやなド初心者ですので、より良いコード、間違った点などがあればご教授頂けると幸いです。
- 投稿日:2019-09-15T00:32:24+09:00
Windows WSL2に移行後 bundle exec rails xxx が激遅だったが解決
解決した方法を先に書くと
WindowsのCドライブなどに置いていたrailsプロジェクトをWSLのUbuntu配下に移動するMac使っていないマンとしてはWSL2を試してみたくなってWindos Insider Programに参加しました。
Windows Insider ProgramとWSLについては簡単にこちらのブログに書きました。
https://blog.higekick.net/wls2/Rails Tutorialをやっているのですが、WSL2に移行後、
bundle exec rails s
とかが遅いことに気づきました。
確かに各種git
コマンドは速くなっている気がします。
なんでかなと思って予想したのがrailsのプロジェクトを置いているディレクトリの位置でした。
wsl2は仮想マシン上で動いているとかなんとか聞いたのですがWindows側から見た時の位置が以下のようになっていました。パスとしてはこんな感じになっていました。
\\wsl$\Ubuntuwsl1の時の位置はちょっと把握していないのですが、Networkの下とかじゃなかったですよね。
本題のrailsプロジェクトですが、WindowsのDドライブに置いてUbuntuのホームディレクトリからシンボリックリンクで参照できるようにしていました。
wsl2に移行後もちゃんとそれは維持されていて、wsl1と同じようにrailsプロジェクトのディレクトリを参照できて、$ code rails-tutorial-sampleapp/
とかでVS CODEで開いてRails Tutorialを楽しむことができました。hige@thkpdE480:~$ pwd /home/hige hige@thkpdE480:~$ ls -la src lrwxrwxrwx 1 hige hige 10 Sep 5 2018 src -> /mnt/d/srcしかしrailsの各種コマンドが遅いのですね。5分くらいでやっとrails serverが立ち上がる感じです。
そこまで待ってみた私もすごいのですが、なんでこんな遅いのか解決したかったです。で、やっぱりこのネットワーク下になってしまった
\\wsl$\Ubuntu
のディレクトリからDドライブのプロジェクトを参照してしまっているからでは?と思ったのですよね。
そこで以下のようにホームディレクトリに配置したら速くなりました。\\wsl$\Ubuntu\home\hige\src2\rails-tutorial-sampleapp実際にはgitでcloneしなおしたのですが、railsプロジェクトなので移動後、railsが起動できるようになるまでどうやったのかメモしておきます。railsプロジェクトをcloneして自分の端末で開発できるようにするときはだいたいこうやるのかなと思っております。
- Ubuntu下のディレクトリでcloneしなおす
$ git clone [リポジトリURL]
- rubyをセットする
$ rbenv local 2.6.1
- gemsをインストールする
$ bundle install --path vendor/bundle
- DBをテスト環境(開発環境?)用にマイグレートする, テストデータを入れる
$ bundle exec rails db:migrate RAILS_ENV=test $ bundle exec rails db:seed
- テストして通ればOK
$ bundle exec rails test
- サーバーが立ち上がってログインし、テストデータが見えればOKとする
$ bundle exec rails serverこれらの
bundle exec rails xxx
コマンドが前みたいに普通の速さで実行できるようになりました。
wsl1の頃よりたぶん速くなっているんですよね!?確かに速くなっている気がします。
Macだとこんな苦労しなくても良さそうだけど、いろいろな制約でWindows使うしかない方とかたくさんいらっしゃると思います。共にがんばりましょう!増税前にMac買ったほうがいいですかね... 2019/09/15
- 投稿日: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