- 投稿日:2020-06-25T23:33:31+09:00
簡単なrender
renderメソッドを使ってなかったので使ってみる。
一番簡単なやつ
index.html.erb<%= render 'sample'%>これで、indexのビューには _sample.html.erb の中身が埋め込まれる。
補足.埋め込まれるファイルは、 <%= render '○○'%> の○○の頭に _をつけたもの。 例えば <%= render 'form'%> であれば_form.html.erbファイルが埋め込まれる。埋め込むビューファイルのことをパーシャルという。
renderを使うことで同じようなビューを使いまわせて楽。_sample.html.erb<h1>これが表示されるよ</h1>変数を渡したいとき
index.html.erb<%= render 'sample2', aaa: @name %>このように書くと@nameをaaaとしてパーシャル内で利用できる。
例えば@nameを渡して
_sample2.html.erb<%= aaa.length %>とすれば@nameの文字数を出力してくれる。
- 投稿日:2020-06-25T22:58:48+09:00
アクション
newアクション
表示してほしいアドレスが送られてきたら、まずルーティングにより処理される。
例えば /pages/new が送られてきたら、
ルートさんはルーティング対応表を見ながら対応するコントローラーとそのアクションを見つける。
「えーと、パスは pages/new で、getメソッドだから・・・pages コントローラーのnewアクションを
呼ぼう」
こうしてpages コントローラーのnewアクションに処理が移る。newアクションの中に
def new
@name=User.new
endのようなものがあれば、Userクラスのインスタンスをつくり、@nameインスタンス変数へ代入し、ビューへ渡す。
インスタンスはクラスをnewしてできたもの。ここで作られたインスタンスは設定により色々格納できるようになっているが中身は空っぽ。
- 投稿日:2020-06-25T22:33:10+09:00
【初学者手順書2】Ruby on Rails :Railsの雛形作成
初学者手順書1の続きです。
今回は、Railsの雛形を作成していきます。Rails雛形作成
Railsアプリケーションを作成
ターミナル上、指定のディレクトリで実行% rails _Ver.指定_ new アプリ名 -d RDBMS名(mysqlなど)ファイルの文字コードの設定(必要な場合)
config/database.yml# m4を削除 encoding: utf8データベース作成
% rails db:create不要なファイルが作成されないように追記(必要な場合)
rails gでコントローラを作成する場合テストファイルなどを自動で作るためconfig/application.rb# 省略 module アプリ名 class Application < Rails::Application config.load_defaults 6.0 config.generators do |g| g.stylesheets false g.javascripts false g.helper false g.test_framework false end end endGitHubコミットされたくないファイルを記載
.gitignorepublic/uploads/*READMEに、データベース設計やアプリの情報を記載していく。
- 投稿日:2020-06-25T22:24:36+09:00
マイグレーション
rails g model モデル名等のコマンドを打つとdbフォルダ内にマイグレーションファイルが作成され、そこでテーブルの管理ができる。
t.string
- 投稿日:2020-06-25T22:19:04+09:00
model
modelについて
rails g model モデル名でモデルを作成。
バリデーションやモデル同士の関連付けなどを記入する。
- 投稿日:2020-06-25T21:18:38+09:00
Rails初心者から中級者までに伝えたい、Controllerのアンチパターン3つ
tl; dr
controllerでは特に、インスタンス変数の濫用はやめよう!
すべてのはじまり
ほとんど触ったことないプロジェクトに移籍させられ早1ヶ月、そのコードを知る熟練の先輩も去った荒廃の地で、私は今日も一人、Railsと激闘を繰り広げていた!
というわけで(?)、今回はcontrollerでやってはいけないアンチパターンを紹介していきたい。クソコード1. インスタンス変数に入れればええやろ
これは初心者がやらかしがちな印象
こういうやつsample_controller.rbclass SampleController < ApplicationController def show hoge = Hoge.new @hoge_kuso1 = hoge.kuso @hoge_kuso2 = hoge.sugoku_kuso @hoge_kuso3 = Hoge.fetch_kuso end end......
こ☆ろ☆す☆ぞ
まず第一に、Railsのコントローラーは一つのディレクトリに入るものをだいたい一つのクラスで固めるので、言い換えれば複数のアクションのロジックが一つのクラスにまとまっている。なので例えば次のようなコードは日常茶飯事である。
sample_controller.rbclass SampleController < ApplicationController def action1 end def action2 end endこの状態で2つのアクションがインスタンス変数をたくさん使ったとしよう。それが以下
sample_controller.rbclass SampleController < ApplicationController def action1 hoge = Hoge.new @hoge_kuso1 = hoge.kuso @hoge_kuso2 = Hoge.fetch_kuso end def action2 hoge = Hoge.new @hoge_kuso1 = hoge.sugoku_kuso @hoge_kuso2 = Hoge.fetch_kuso end ... endついでに
Hoge
クラスはこうhoge.rbrequire 'rest-client' class Hoge def kuso :kuso end def sugoku_kuso "sugoku kuso" end def self.fetch_kuso RestClient.get('https://kuso.com/kuso3').body rescue 'honma kuso' end endこの状態の何が悪いのかというと、インスタンス変数をたくさん使ったことにより、コード全体でどの変数がどこに所属しているのかが分かりにくいことだ。例えば
@hoge_kuso1
はクラス内スコープの変数であるので、もしかしたら他のところの定義とコンフリクトしてバグるかもしれない。それにクラス内検索しても複数の全然関係ない奴が引っかかる可能性もあるので、補足もしづらい。あんまりメリットはないのである。解決策
単純な話、極力インスタンス変数を使わないことだ。具体的にはこう。
sample_controller.rbclass SampleController < ApplicationController def action1 @hoge = Hoge.new end def action2 @hoge = Hoge.new end ... endhoge.rbrequire 'rest-client' class Hoge def kuso :kuso end def sugoku_kuso "sugoku kuso" end # 要素をモデルからアクセスできるようにして、controller上でインスタンス変数を使う可能性をを極力排除する def fetched_kuso @fetched_kuso ||= self.class.fetch_kuso end def self.fetch_kuso RestClient.get('https://kuso.com/kuso3').body rescue 'honma kuso' end endどういうことかというと、インスタンス変数に入れるのはモデル程度にしておいて、詳細なデータはモデル内に内包してしまおう、ということだ。これのメリットは2つ
- コントローラーがスッキリする
- ロジックが複数の場所に依らない
正直メリットしかないので、やらない手はないと思う。ちなみにたとえば複数のモデルに対して一括で値を取得したいんだけど、その場合はどうするの?ということについては
sample_controller.rbclass SampleController < ApplicationController def action1 @hoges = 10.times.map { Hoge.new } Hoge.set_kusos(@hoges) end endhoge.rbrequire 'rest-client' class Hoge def kuso :kuso end def sugoku_kuso "sugoku kuso" end attr_accessor :fetched_kuso # 専用のセッター def self.set_kusos(hoges) hoges.each do |hoge| hoge.fetched_kuso = self.fetch_kuso end end def self.fetch_kuso RestClient.get('https://kuso.com/kuso3').body rescue 'honma kuso' end endとするなどして、モデル内にデータを保持するといい。とにかくコントローラーで無闇にロジックを書かないようにすることは大事である。
クソコード2. set_〇〇って書いとけば安泰やろ。其の壱
ダメです
例えばこう書く人はほとんどだと思うsample_controller.rbclass SampleController < ApplicationController before_action :set_hoge, only: :action1 def action1 end private def set_hoge @hoge = Hoge.new end end絶対10人に9人はこう書いてる。なぜならscaffoldでもこう書くのを推奨してるから。
じゃあこれの何がダメなのかというと、以下の2つ
- コードが追いにくい
- 引数を渡しにくい
まず1について
sample_controller.rbclass SampleController < ApplicationController before_action :set_hoge, only: :action1 before_action :set_hoges, only: :action2 def action1 end def action2 end private def set_hoge @hoge = Hoge.new end def set_hoges @hoges = [Hoge.new, Hoge.new] end endこう書かれた場合に、action1を確認した瞬間、あ、これは
@hoge
を使うんだな、ってなる人はいないだろう。
少なくとも、
action1がなにも定義されていない -> あ、before_actionが定義されているということはつまり -> やっぱり@hoge
を使っていたか
となるのではないだろうか?
これはアハ体験としては適切な体験かもしれないが、コーディングに脳科学を持ち込まないでほしい。はっきり言ってストレスである。また、 クソコード1でも述べたように、コントローラー内で使用されるインスタンス変数は所在がわかりにくくなりがちである。よってインスタンス変数を無闇に使うのはよろしくない。
次に2について
sample_controller.rbclass SampleController < ApplicationController before_action(only: :action1) do set_hoge('fuga') end def action1 end private def set_hoge(fuga) @hoge = Hoge.new(fuga) end endこうしないと変数が渡せない。逆にこれだったら渡せるじゃん?という諸君。確かに渡せるが、これだとせっかく便利なskip_before_actionが利用できない。そこまでしてset_〇〇を使う必要ある?という気持ちでいっぱいである。
解決策
答えは単純である。
sample_controller.rbclass SampleController < ApplicationController def action1 @hoge = fetch_hoge end private def fetch_hoge Hoge.new end endこれであれば、インスタンス変数がロジック内に組み込まれているので、見た瞬間に
@hoge
を使うことがわかる。また引数を渡すのも容易である。とってもスマート、故にハッピー。また、これだとredirect_toを書くのに手間がかかるじゃん!そっちはどうすんのさ!?っていうみなさんのために、以下のコードを授けよう
sample_controller.rbclass SampleController < ApplicationController class DataNotFound < RuntimeError; end rescue_from DataNotFound do redirect_to :root_path, flash: { error: 'データが見つかりませんでした' } end def action1 @hoge = fetch_hoge end private def fetch_hoge hoge = Hoge.new raise DataNotFound unless hoge hoge end endこれであれば元々の機能を維持できるだろう。
クソコード3. set_〇〇って書いとけば安泰やろ。其の弐
ダメだって言ってんだろ!!!
場合にもよるけど、例えばヘッダーで使う値をこうやって作る人いるよねsample_controller.rbclass SampleController < ApplicationController before_action :set_header_de_tukau_yatu def set_header_de_tukau_yatu @header_info = 'void' end endこれの問題点は「
@header_info
を利用する」ためには、「:set_header_de_tukau_yatu
を呼び出す」必要があることを知っていなきゃいけないことだ。この場合、viewがほしいのは@header_info
だけ、なのになぜその設定方法までこっちが把握してなきゃいかんの?っていう話解決策
こういうときにどうすればいいのかというと helper_methodを使う。例えば以下
sample_controller.rbclass SampleController < ApplicationController helper_method :header_info def header_info @header_info ||= 'void' end endこうすることで、viewは
header_info
を呼び出すと、情報が得られる。ということを知っているだけでいい。わざわざ内部のロジックまで知る必要もないし、インスタンス変数もロジックに近い場所にある。とっても素晴らしい。おわりに
この記事ではアンチパターンを3つしか紹介していないが、多分世の中にはもっとたくさんのアンチパターンがあると思う。しかし多くの場合、それは「可読性が下がる」「使い勝手が悪い」のいずれかないし両方を満たしているのではなかろうか?そしてその二つを生み出しがちな諸悪の根源、それはインスタンス変数の濫用である(暴論。今回本当に伝えたかったことはただ一つ。みなさんご唱和ください。
インスタンス変数の濫用はやめよう!!!!!
読了ありがとうございました。
- 投稿日:2020-06-25T21:18:38+09:00
Rails初心者から中級者までに伝えたい、アンチパターン3つ
tl; dr
controllerでは特に、インスタンス変数の濫用はやめよう!
すべてのはじまり
ほとんど触ったことないプロジェクトに移籍させられ早1ヶ月、そのコードを知る熟練の先輩も去った荒廃の地で、私は今日も一人、Railsと激闘を繰り広げていた!
というわけで(?)、今回はcontrollerでやってはいけないアンチパターンを紹介していきたい。クソコード1. インスタンス変数に入れればええやろ
これは初心者がやらかしがちな印象
こういうやつsample_controller.rbclass SampleController < ApplicationController def show hoge = Hoge.new @hoge_kuso1 = hoge.kuso @hoge_kuso2 = hoge.sugoku_kuso @hoge_kuso3 = Hoge.fetch_kuso end end......
こ☆ろ☆す☆ぞ
まず第一に、Railsのコントローラーは一つのディレクトリに入るものをだいたい一つのクラスで固めるので、言い換えれば複数のアクションのロジックが一つのクラスにまとまっている。なので例えば次のようなコードは日常茶飯事である。
sample_controller.rbclass SampleController < ApplicationController def action1 end def action2 end endこの状態で2つのアクションがインスタンス変数をたくさん使ったとしよう。それが以下
sample_controller.rbclass SampleController < ApplicationController def action1 hoge = Hoge.new @hoge_kuso1 = hoge.kuso @hoge_kuso2 = Hoge.fetch_kuso end def action2 hoge = Hoge.new @hoge_kuso1 = hoge.sugoku_kuso @hoge_kuso2 = Hoge.fetch_kuso end ... endついでに
Hoge
クラスはこうhoge.rbrequire 'rest-client' class Hoge def kuso :kuso end def sugoku_kuso "sugoku kuso" end def self.fetch_kuso RestClient.get('https://kuso.com/kuso3').body rescue 'honma kuso' end endこの状態の何が悪いのかというと、インスタンス変数をたくさん使ったことにより、コード全体でどの変数がどこに所属しているのかが分かりにくいことだ。例えば
@hoge_kuso1
はクラス内スコープの変数であるので、もしかしたら他のところの定義とコンフリクトしてバグるかもしれない。それにクラス内検索しても複数の全然関係ない奴が引っかかる可能性もあるので、補足もしづらい。あんまりメリットはないのである。解決策
単純な話、極力インスタンス変数を使わないことだ。具体的にはこう。
sample_controller.rbclass SampleController < ApplicationController def action1 @hoge = Hoge.new end def action2 @hoge = Hoge.new end ... endhoge.rbrequire 'rest-client' class Hoge def kuso :kuso end def sugoku_kuso "sugoku kuso" end # 要素をモデルからアクセスできるようにして、controller上でインスタンス変数を使う可能性をを極力排除する def fetched_kuso @fetched_kuso ||= self.class.fetch_kuso end def self.fetch_kuso RestClient.get('https://kuso.com/kuso3').body rescue 'honma kuso' end endどういうことかというと、インスタンス変数に入れるのはモデル程度にしておいて、詳細なデータはモデル内に内包してしまおう、ということだ。これのメリットは2つ
- コントローラーがスッキリする
- ロジックが複数の場所に依らない
正直メリットしかないので、やらない手はないと思う。ちなみにたとえば複数のモデルに対して一括で値を取得したいんだけど、その場合はどうするの?ということについては
sample_controller.rbclass SampleController < ApplicationController def action1 @hoges = 10.times.map { Hoge.new } Hoge.set_kusos(@hoges) end endhoge.rbrequire 'rest-client' class Hoge def kuso :kuso end def sugoku_kuso "sugoku kuso" end attr_accessor :fetched_kuso # 専用のセッター def self.set_kusos(hoges) hoges.each do |hoge| hoge.fetched_kuso = self.fetch_kuso end end def self.fetch_kuso RestClient.get('https://kuso.com/kuso3').body rescue 'honma kuso' end endとするなどして、モデル内にデータを保持するといい。とにかくコントローラーで無闇にロジックを書かないようにすることは大事である。
クソコード2. set_〇〇って書いとけば安泰やろ。其の壱
ダメです
例えばこう書く人はほとんどだと思うsample_controller.rbclass SampleController < ApplicationController before_action :set_hoge, only: :action1 def action1 end private def set_hoge @hoge = Hoge.new end end絶対10人に9人はこう書いてる。なぜならscaffoldでもこう書くのを推奨してるから。
じゃあこれの何がダメなのかというと、以下の2つ
- コードが追いにくい
- 引数を渡しにくい
まず1について
sample_controller.rbclass SampleController < ApplicationController before_action :set_hoge, only: :action1 before_action :set_hoges, only: :action2 def action1 end def action2 end private def set_hoge @hoge = Hoge.new end def set_hoges @hoges = [Hoge.new, Hoge.new] end endこう書かれた場合に、action1を確認した瞬間、あ、これは
@hoge
を使うんだな、ってなる人はいないだろう。
少なくとも、
action1がなにも定義されていない -> あ、before_actionが定義されているということはつまり -> やっぱり@hoge
を使っていたか
となるのではないだろうか?
これはアハ体験としては適切な体験かもしれないが、コーディングに脳科学を持ち込まないでほしい。はっきり言ってストレスである。また、 クソコード1でも述べたように、コントローラー内で使用されるインスタンス変数は所在がわかりにくくなりがちである。よってインスタンス変数を無闇に使うのはよろしくない。
次に2について
sample_controller.rbclass SampleController < ApplicationController before_action(only: :action1) do set_hoge('fuga') end def action1 end private def set_hoge(fuga) @hoge = Hoge.new(fuga) end endこうしないと変数が渡せない。逆にこれだったら渡せるじゃん?という諸君。確かに渡せるが、これだとせっかく便利なskip_before_actionが利用できない。そこまでしてset_〇〇を使う必要ある?という気持ちでいっぱいである。
解決策
答えは単純である。
sample_controller.rbclass SampleController < ApplicationController def action1 @hoge = fetch_hoge end private def fetch_hoge Hoge.new end endこれであれば、インスタンス変数がロジック内に組み込まれているので、見た瞬間に
@hoge
を使うことがわかる。また引数を渡すのも容易である。とってもスマート、故にハッピー。また、これだとredirect_toを書くのに手間がかかるじゃん!そっちはどうすんのさ!?っていうみなさんのために、以下のコードを授けよう
sample_controller.rbclass SampleController < ApplicationController class DataNotFound < RuntimeError; end rescue_from DataNotFound do redirect_to :root_path, flash: { error: 'データが見つかりませんでした' } end def action1 @hoge = fetch_hoge end private def fetch_hoge hoge = Hoge.new raise DataNotFound unless hoge hoge end endこれであれば元々の機能を維持できるだろう。
クソコード3. set_〇〇って書いとけば安泰やろ。其の弐
ダメだって言ってんだろ!!!
場合にもよるけど、例えばヘッダーで使う値をこうやって作る人いるよねsample_controller.rbclass SampleController < ApplicationController before_action :set_header_de_tukau_yatu def set_header_de_tukau_yatu @header_info = 'void' end endこれの問題点は「
@header_info
を利用する」ためには、「:set_header_de_tukau_yatu
を呼び出す」必要があることを知っていなきゃいけないことだ。この場合、viewがほしいのは@header_info
だけ、なのになぜその設定方法までこっちが把握してなきゃいかんの?っていう話解決策
こういうときにどうすればいいのかというと helper_methodを使う。例えば以下
sample_controller.rbclass SampleController < ApplicationController helper_method :header_info def header_info @header_info ||= 'void' end endこうすることで、viewは
header_info
を呼び出すと、情報が得られる。ということを知っているだけでいい。わざわざ内部のロジックまで知る必要もないし、インスタンス変数もロジックに近い場所にある。とっても素晴らしい。おわりに
この記事ではアンチパターンを3つしか紹介していないが、多分世の中にはもっとたくさんのアンチパターンがあると思う。しかし多くの場合、それは「可読性が下がる」「使い勝手が悪い」のいずれかないし両方を満たしているのではなかろうか?そしてその二つを生み出しがちな諸悪の根源、それはインスタンス変数の濫用である(暴論。今回本当に伝えたかったことはただ一つ。みなさんご唱和ください。
インスタンス変数の濫用はやめよう!!!!!
読了ありがとうございました。
- 投稿日:2020-06-25T20:18:49+09:00
rails routes(ルーティング)の順番の解説
自分用のまとめ
https://qiita.com/gawach/items/4e7460d06f70e3013eea
にてまとめられているが、私は違う理解の仕方をしている。
それを説明します。⑴ 1 get "posts/:id" => "posts#show" 2 get "posts/new" => "posts#new"⑵ 3 get "posts/new" => "posts#show" 4 get "posts/:id" => "posts#new"⑶(プロゲートに書いてあった正しいコード) get "posts/index" => "posts#index" get "posts/:id" => "posts#show"⑴は間違いであり、⑵は実は正しいと決める、それを下記に示す。
上から順にコードを優先していくため、
:id以外の特定のURLが:idより先にくるようにする。
そしてそれら以外の余ったものが:idの対象となる。
上記のようなルールがあるため、
:idはposts/newのようなURLより先に記述されているとエラーになる。
- 投稿日:2020-06-25T20:15:51+09:00
【Rails】lazy_high_chartsを用いてグラフを作成する方法
目標
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
下記実装済み。
・Slim導入
・Bootstrap3導入
・Font Awesome導入
・ログイン機能実装
・投稿機能実装実装
1.Gemを導入
Gemfile# 追記 gem 'lazy_high_charts'ターミナル$ bundle2.
application.js
を編集application.js//= require rails-ujs //= require activestorage //= require turbolinks //= require highcharts/highcharts // 追記 //= require highcharts/highcharts-more // 追記 //= require_tree .3.コントローラーを編集
books_controller.rbdef index @book = Book.new @books = Book.all # 追記 days = (Date.today.beginning_of_month..Date.today).to_a books = days.map { |item| Book.where(created_at: item.beginning_of_day..item.end_of_day).count } @graph = LazyHighCharts::HighChart.new('graph') do |f| f.title(text: '本 月間登録推移') f.xAxis(categories: days) f.series(name: '登録数', data: books) end end① 今月1日から今日までの日付を取得し、変数へ代入する。
days = (Date.today.beginning_of_month..Date.today).to_a②
①
で取得した日付内に作成された本の数を取得し、変数へ代入する。books = days.map { |item| Book.where(created_at: item.beginning_of_day..item.end_of_day).count }③ グラフを作成する
@graph = LazyHighCharts::HighChart.new('graph') do |f| f.title(text: '本 月間登録推移') # タイトル f.xAxis(categories: days) # 横軸 f.series(name: '登録数', data: books) # 縦軸 end4.ビューを編集
books/index.html.slim/ 追記 = high_chart('sample', @graph)
- 投稿日:2020-06-25T19:53:52+09:00
bundle config --global build.mysql2 でエラー
新アプリケーションを作成する前段階で起きた話(一部ユーザー名に編集加えてます)。
bundlerの構成オプションをいじろうとして以下のコマンドを入力
bundle config --global build.mysql2 --with-opt-dir="$(brew --prefix openssl)"するとこんなエラーが...
There was an error while trying to write to /Users/hoge/.bundle/config. It is likely that you need to grant write permissions for that path.
ターミナルから「configをいじる権限ないよ。おととい来やがれ」と言われてしまいました・・・・・・(過激)。
.configがどうなっているか確認したいなと思い以下のコマンドを入力
% cd .bundle % cd .config
すると不可思議なことが発生する
cd: no such file or directory: .config
!!??
.config がないって・・・どういうこと・・・?
なんでだろう・・・と思って権限の確認を行うために以下のコマンドを入力
% cd % ls -ls
すると権限一覧がこちら
※一部抜粋 drwxr-xr-x+ 51 hoge staff 1632 6 25 19:41 . drwxr-xr-x 6 root admin 192 3 3 20:00 .. -r-------- 1 hoge staff 7 3 27 23:03 .CFUserTextEncoding -rw-r--r--@ 1 hoge staff 18436 6 24 10:28 .DS_Store drwx------@ 286 hoge staff 9152 6 23 18:06 .Trash -rw-r--r-- 1 hoge staff 1 5 23 15:13 .bash_profile -rw------- 1 hoge staff 12288 4 30 11:58 .bashrc.swp drwxr-xr-x 4 root staff 128 4 16 17:02 .bundle drwxr-xr-x 3 hoge staff 96 4 3 13:42 .gem
.bundleがrootになってる!!!!
ということで以下のコマンド入力して権限者を変更しましょう。
sudo chown -R [権限を与えたいユーザー名] .bundle
今回ダミー名の「hoge」を入力。
sudo chown -R hoge .bundle
解決!!!!
同様のエラーが生じた際の参考になれば幸いです!
- 投稿日:2020-06-25T19:28:01+09:00
Cloud9がメモリー足りないってよ: Railsチュートリアル備忘録
Cloud9がメモリー足りないってよ: Railsチュートリアル備忘録
Cloud9に以下のメッセージが出てコンソールが固まる事態に
This environment is running low on memory (132 MB of virtual memory left).
To free up memory, kill processes by choosing "Tools > Process List" in the menu bar.
To migrate this environment to one that has more memory, ...解決法
EC2インスタンスを再起動する
経緯
Railsチュートリアル13章進行中のこと
トリガーもよくわからいのですがTestを走らせると... Missing helper file helpers/microposts_helper.rb ...
といったエラーのが出るように
bundle update
するといいよとの記事があったため
試してみたところCloud9上で上記通知がでるように...
ググってみてもあまり情報がなく
いっそ試してみたかったDockerを利用して環境再構築...なんて考えましたが結局EC2インスタンスを再起動することで2つとも解決しました
インスタンスの再起動 - Amazon Elastic Compute Cloud
いまさらですがオンラインIDEであるCloud9は
AWSの一部であるEC2サービスで提供される
仮想サーバー(これがEC2インスタンス)上で動いているわけですねインスタンスという言葉がすっと頭に馴染むようになってきたこととに喜び、
AWSの全体像について視野が広がったという学びでした
- 投稿日:2020-06-25T19:04:03+09:00
Gem simple calendarでのカレンダー実装と条件分岐
概要
現在DMMWEBCAMPというプログラミングスクールで学習しておりまして、
ポートフォリオ作成にあたりイベントテーブルを作成してカレンダーに表示させました。
これから作成する方のお役に立てればと思います。完成図
参考にさせて頂いた記事
【Rails】Simple Calendarを使ったカレンダー表示
https://qiita.com/mikaku/items/0971442a7308dc669122github
https://github.com/excid3/simple_calendar事前準備
イベントテーブル
・data_and_timeがスタートする日時
・meetingfinishtimeが終了する日時イベント参加テーブル
アソシエーション
models/event.rbclass Event < ApplicationRecord has_many :event_participates, dependent: :destroy endmodels/event_participate.rbclass EventParticipate < ApplicationRecord belongs_to :event endgem install
gem 'simple_calendar', '~>2.0'$ bundle installSimple calendarのViewインストール
$ rails g simple_calendar:views・views/simple_calendar内に3種類のカレンダーの雛形が出来ます。
application.scss(CSS)への記載
stylesheets/applecation.scss*= require simple_calendar *= require_tree . *= require_selfstart_time end_timeの定義
models/event.rbclass Event < ApplicationRecord has_many :event_participates, dependent: :destroy def start_time self.date_and_time end def end_time self.meetingfinishtime end endこのgemではstart_timeとend_timeの定義が必要です。(特にstart_time)
作成しているカラムが最初からその名前であれば良いのですが、違うカラム名なのであればモデルの方で定義しましょう。ただし日付と時刻を扱うのでデータ型は恐らくdatetime型でなければならないと思います。
最初定義せずに実装したところエラーが出ました。githubではscaffoldを使用して最初から上記名称でカラムを作成しておりました。
カレンダーの表示
私のポートフォリオ
views/events/index.html.erb</div> <div class= 'calender'> <%= month_calendar events: @events do |date, event| %> <%= date %> <% event.each do |event| %> <br> <% if user_signed_in? %> <% if event.user_id == current_user.id %> <i class="fa fa-circle notification-circle" style="color: red;"></i> <% end %> <% end %> <% if event.event_participates.where(user_id: current_user).exists? %> <span class="participate"> <%= link_to event.title,event_path(event) %> </span> <% else %> <span class="other"> <%= link_to event.title,event_path(event) %> </span> <% end %> <% end %> <% end %> </div>カレンダーの表示とイベントのタイトルだけであれば以下のみで良いです。
<div class= 'calender'> <%= month_calendar events: @events do |date, event| %> <%= date %> <% event.each do |event| %> <%= event.title %> <% end %> <% end %> </div>controllers/events_controller.rbdef index @events = Event.all endコントローラーで定義しているEvent.allを@eventsに格納しカレンダーで表示しています。
<%= month_calendar events: @events
この構文の中のevents:は恐らく変えるとエラーが出ますが、インスタンス変数は情報が格納されていればどんなものを使用しても大丈夫だと思います。現在は先ほどインストールしたmonth_calendarを使用していますが、他に2つテンプレートが用意されているので3種類から使用することが出来るようです。
私は参加(participate)アクションを取っていればbackground-colorをオレンジに、
主催しているイベントであれば赤丸のアイコンを付けたかったので以下のような条件分岐を
カレンダー内で行いました。<% if event.user_id == current_user.id %> <i class="fa fa-circle notification-circle" style="color: red;"></i> <% end %>イベントテーブルの中のuser_id(つまりイベント作成者)が自分であればイベントタイトルの前にfont awesomeのアイコンを表示というものです。インライン要素のものであればここは何でも良いと思います。
次に
<% if event.event_participates.where(user_id: current_user).exists? %> <span class="participate"> <%= link_to event.title,event_path(event) %> </span> <% else %> <span class="other"> <%= link_to event.title,event_path(event) %> </span> <% end %>1行目の <% if event.event_participates.where(user_id: current_user).exists? %>で
eventに参加(participete)するユーザーの中に自分(current_user)が存在しているかどうかを探しています。
見つかればclass participate、そうでなければclass otherとすることで、
表示する情報は同じでもclass名が違うという状態にすることが出来ました。後はCSSで色を変えていくだけなので、皆さんのお好みのようにしていただければと思います。
ちなみにmonth_calenderのviewは以下です。
views/simple_calendar/_month_calendar.html.erb<div class="simple-calendar"> <p class="carendar-title"><%= "#{Date.today.month}月のイベントスケジュール" %></p> <div class="calendar-heading" data-turbolinks="false"> <!--%= link_to t('simple_calendar.previous', default: 'Previous'), calendar.url_for_previous_view %--> <!-- <span class="calendar-title"><%= t('date.month_names')[start_date.month] %> <%= start_date.year %></span> --> <!--%= link_to t('simple_calendar.next', default: 'Next'), calendar.url_for_next_view %--> <i class="fa fa-circle notification-circle" style="color: red;"><span>主催イベント</span></i> <span class="calendar-info">参加予定</span> </div> <table class="table table-striped calendar-table"> <thead> <tr> <% date_range.slice(0, 7).each do |day| %> <th><%= t('date.abbr_day_names')[day.wday] %></th> <% end %> </tr> </thead> <tbody> <% date_range.each_slice(7) do |week| %> <tr> <% week.each do |day| %> <%= content_tag :td, class: calendar.td_classes_for(day) do %> <% if defined?(Haml) && respond_to?(:block_is_haml?) && block_is_haml?(passed_block) %> <% capture_haml(day, sorted_events.fetch(day, []), &passed_block) %> <% else %> <% passed_block.call day, sorted_events.fetch(day, []) %> <% end %> <% end %> <% end %> </tr> <% end %> </tbody> </table> </div>私のポートフォリオの仕様で上の部分をコメントアウトしています。
コメントアウトの場所に本来であれば次月や前月へのリンクが出てきます。
細かいところであれば柔軟に変えれそうです。まとめ
最初はfullcalendarでの実装を目論んだのですが、理解が及ばず諦めて今回こちらのgemを使用しました。イベントタイトルがstart_timeとend_timeの間で毎回出てしまうことを改善できればと思ったのですが私の力不足で難しかったです。
要素のclass名に特に意味はありません。スペルを所々間違えてますが、、
このぐらい簡単なカレンダーでも見せ方次第で私のものよりもっといいものになると思うので是非やってみてください。
- 投稿日:2020-06-25T18:36:34+09:00
AWSでデプロイしちゃおうってわけ(AWS登録編)
こんばんはですね。
お久しぶりになってしまい非常に私反省しております。
昨日は地震が酷かったですね。
寝ていて若干起きたけど、眠気に負けてすぐ寝ましたが。気になったのはニュースで
「余震には気をつけましょう!」
っていってるけど気をつけようがないだろ!!!予測できないんだし!!!
と思ってしまう私は悪い子でしょうか。
さて今回はデプロイに関してAWSを使ってデプロイしていくわよっ!!
1 まずはAWSのHPへアクセスっ!!
こちらから飛んで頂戴
AWSそんで右上への無料サインアップから登録して頂戴!!
※住所、電話番号を登録するページで一番下でアーグリメント〜って聞かれるからそれはチェックしておく様に!!
2 クレジットカート登録+電話番号認証
若いアンタ達なら画像無しでも出来るハズダワ。。。。
その次にプランを選ぶところがあるから
有無を言わさずベーシック無料プラン!!!!!!
これで準備完了よ。
次はインスタンスとかなんちゃらとかやっていくわよ!!!!
- 投稿日:2020-06-25T18:21:25+09:00
�Rails + Heroku でメール認証
概要
Railsアプリのメール認証をHerokuの本番環境で実装しました。
当初はRailsチュートリアルの通りSendGridを使用していたのですが、すぐにアカウントが凍結されてしまい一歩も先に進めなかったのでGmailに切り替えました。logを確認したらNet::SMTPAuthenticationErrorの一文があったので、SendGridではなくそもそもGmailでエラーを起こしていた可能性も...?
SendGridで送信に失敗する場合確認するべきこと
存在するメールアドレスへ送信しているか?
開発環境でgemの「letter_opener_web」などを使用している場合、「test@mail.com」のような架空のアドレスでも送信をすることができましたが、本番環境では送信できません。(そもそもアドレスがなきゃ届かない...)
私ほどの間抜けでなければしないミスでしょうが、タイポの確認は最初にしてみても損はないでしょう。Net::SMTPAuthenticationErrorが出ていないか?
送信元アドレスにGmailを設定している場合、「2 段階認証プロセス」をオンにしていないとエラーが発生するようです。
(他のメールサービスでも同様のセキュリティがあるのかな?)
次のコマンドから確認ができます。heroku logs --tail
正常に送信されていれば次のようにメールの内容が表示されるので、どちらにしてもログは確認しておいたほうがいいでしょう。
From: please-change-me-at-config-initializers-devise@example.com Reply-To: please-change-me-at-config-initializers-devise@example.com To: test@mail.com Message-ID: <5ef461204d29d_475308ddc-2ec6f04e388a.mail> Subject: =?UTF-8?Q? Mime-Version: 1.0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: base64 ~メール本文~SendGridのアカウントを凍結されていないか?
Railsチュートリアルに倣ってコンソールからSendGridに登録するとほぼ確実に凍結されました。(私は5/5で凍結されました...)
登録後すぐはHerokuのダッシュボード画面にある「Installed add-ons」のSendGridをクリックすると、SendGridへアクセスできるのですが、一度メールの送信に失敗するとクリックしてもアクセスが出来なくなりました。
この状態になるとアカウントが凍結されており、新しくappを作成し直すかSendGrid社へコンタクトを取って凍結を解除してもらうしかないようです。
ちなみに、SendGridで検索してトップに出てくる日本語ページ(構造計画研究所)ではサポート対象外になっているので本社に英語でコンタクトを取らなければならないようです。
Azure marketplace等のアドオンとしてSendGridを利用していますが、日本語サポートは受けられますか?GmailのSMTPを利用する
Googleアカウントに2段階認証をオンにする
Googleアカウント管理画面の「セキュリティ」 > 「二段階認証プロセス」から設定をして二段階認証をオンにしてください。
コードの追加
config/environments/production.rb# herokuでメールを送信するための設定 config.action_mailer.delivery_method = :smtp host = "#{ENV['HEROKU_APPNAME']}.herokuapp.com" config.action_mailer.default_url_options = { host: host, protocol: 'https' } ActionMailer::Base.smtp_settings = { :address => 'smtp.gmail.com', :port => '587', :authentication => :plain, :user_name => ENV['GMAIL_USERNAME'], :password => ENV['GMAIL_PASSWORD'], :domain => 'gmail.com', :enable_starttls_auto => true }{ENV['HEROKU_APPNAME']}は、変数にせず直接アプリの名前を入力しても問題ありません。
Herokuの環境変数を設定
バッシュボードの「Settings」 > 「Config Vars」で「Reveal Config Vars」をクリックすると環境変数の設定が出来ます。
コンソールからも出来ますがこちらの方が分かりやすいのでいつもこっちを使っています。Key => Value
GMAIL_USERNAME => 送信元に設定するメールアドレス
GMAIL_PASSWORD => 二段階認証の設定で取得したパスワード
HEROKU_APPNAME => Herokuで設定しているアプリ名参考
Heroku Add-onsのSendGridトラブルシューティング
Railsでgmailでメールを送ろうとしたけどsmtp認証のエラーが出て詰まった時の解決方法
- 投稿日:2020-06-25T18:16:14+09:00
CronをDocker上で動かす
概要
- バージョン: Ruby 2.6.5 Rails 5.2.4
- 開発環境: Docker/docker-compose
実現したいこと
- cronを使ってRailsのバッチ処理を実現したい
- Docker環境で動かしたい
BusyBoxの利用がお勧め
元々、Wheneverを使って設定したcronをDocker上で動かそうとしていました。
Docker環境だとcronが動かないようなので、色々な記事を参考にし各種ファイルの設定を行いました。
しかし、cronが動かない。Dockerコンテナに入りエラーログを調べ、対応しても上手くいきませんでした。
ちなみに、エラーログとその対応は以下になります。
log/crontab.logbundler: failed to load command: bin/rails (bin/rails)log/crontab_error.logActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: ["default", "development", "test"]以下の記事を参考にし、
https://www.cotegg.com/blog/?p=1606
schedule.rbに環境変数を渡す記述をしたり、database.ymlにproductionデータベースを構成する記述を追記したりしました。cronの再起動を行い、再びlogファイルを確認しましたが、再度同じエラーが吐かれてしまいました。
恐らく、環境変数を上手く渡せていなかったり、Docker 上でのcron の実行環境が、うまく開発環境と認識されていないことが原因だったのではないかと思います。
私の場合は、結局Wheneverを使って設定したcronをDocker上で動かすことができませんでした。
そこで、この問題が比較的簡単に解決してくれたのが、
BusyBoxという方法です。BubyBoxのメリット
以下のDocker上でcronを使用する際の課題を解決し、シンプルに定期実行をしてくれます。
- cronで実行するプログラムにコンテナに設定した環境変数を渡したい。
- cronは環境変数が独立している
- いちいちファイルに書き出し、読み込みが必要
- ログが標準出力・標準エラー出力されない
BusyBoxのインストール(Debian系)
※AlpineLinuxの場合、crondで使えるようです
apt-get install -y busybox-static
ディレクトリ構成
.
|- Dockerfile
|- crontab
|- docker-compose.yml
|- main.shDockerfile
DockerfileFROM ruby:2.6.5 # インストール RUN apt-get update && apt-get install -y \busybox-static \ # タイムゾーン設定 ENV TZ=Asia/Tokyo # mai.shファイルをコピー COPY ./main.sh /myapp CMD ["busybox", "crond", "-l", "8", "-L", "/dev/stderr", "-f"]crontab
テスト用に1分毎に実行します
* * * * * /app/main.shdocker-compose.yml
crontabファイルをマウントすることで、外部から実行時間を指定できるようになります。
docker-compose.ymlversion: '3' services: busybox: build: . volumes: - ./crontab:/var/spool/cron/crontabs/rootmain.sh
権限エラーを防ぐために、ターミナル上で以下を実行します。
chmod +x main.shテストとして、Dateを出力します。
main.shdate
実行
docker-composeで実行する場合
docker-compose build # Dockerイメージをビルド docker-compose up -d # docker-compose.ymlの変更を反映させる docker-compose logs -f # ログ出力1分毎に、dateを出力できました!
参考にした記事
- 投稿日:2020-06-25T18:16:00+09:00
Rails×Heroku環境でSSL化したときhttp->httpsにリダイレクトさせる方法
config/environments/production.rb# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. config.force_ssl = true # ←ここがコメントアウトされてるので解除するだけ公式ドキュメント
https://help.heroku.com/J2R1S4T8/can-heroku-force-an-application-to-use-ssl-tls
- 投稿日:2020-06-25T16:01:03+09:00
slimの始め方
slimのインストール
アプリのフォルダ内でslimをインストールする。
gem install slimこれで拡張子が.html.slimのslimファイルを、みなさんが普段使っている.html.erbとして変換されるようになるそうです。
gem install html2slimこれでhtml.erb → html.slim に変換させることができるようになるそうです。
bundle exec erb2slim app/views app/viewsこれでエラーが出た場合は、gemfileに下記の2文を追加してbundle installします。
gem 'slim-rails' gem 'html2slim'bundle installこれでviewフォルダに元からあったerbファイルを削除するそうです。
※拡張子が.erbのファイルがない場合は、飛ばしてよし。bundle exec erb2slim app/views app/views -d今後自動的にslimファイルを作成されるようにするためには 、
config/application.rbにあるconfigを以下のようにslimを指定すればOK。config/application.rbmodule App class Application < Rails::Application config.generators.template_engine = :slim #slimに変更 end endslimファイルを表示させる前の準備
rails g controller tweetsviewフォルダのなかに、tweetsフォルダができています。
そのなかにindex.html.slimというファイルを新しく作ります。
そのファイルの中に分かりやすいように何か書いておきましょう。views/tweets/index.html.slimHello, world!コントローラーの中にindexアクションを追加しておきます。
controllers/tweets_controller.rbclass ArchivesController < ApplicationController def index end end次にルーティングです。
config/routes.rbRails.application.routes.draw do root "tweets#index" endサーバーを再起動して、ページを表示
サーバーの再起動を忘れないようにしましょう。
再起動しないままだと、「ArchivesController#index is missing a template for request formats: text/html」というようなエラーが出ます。参考記事
- 投稿日:2020-06-25T14:20:12+09:00
rails ルーティング
- 投稿日:2020-06-25T13:54:16+09:00
【バリデーション】rails 今日の日付以降を指定する方法
【ゴール】
日付入力の際に、今日以降の日付しか入力できないように
バリデーションをかける【メリット】
■ UXの向上
■ validate理解度向上【開発環境】
■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7【実装】
※任意のメソッド名でvalidateを作成
※メソッドの処理を追記
①「return if start_day.blank?」 で空かどうか判断
②「if start_day < Date.today」で今日の日付を取得 & 条件分岐 & 比較
③「errors.add」でエラー文もついでに定義
model/item.rbvalidate :date_before_start validate :date_before_finish def date_before_start return if start_day.blank? errors.add(:start_day, "は今日以降のものを選択してください") if start_day < Date.today end def date_before_finish return if finish_day.blank? || start_day.blank? errors.add(:finish_day, "は開始日以降のものを選択してください") if finish_day < start_day end以上!!
【合わせて読みたい】
■RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い
https://qiita.com/jnchito/items/cae89ee43c30f5d6fa2c■ 【ERROR メッセージ表示】rails 部分テンプレートでいつでも使える 簡易版
https://qiita.com/tanaka-yu3/items/63b189d3f15653cae263■ 【Date.today】 今日だけの情報を取り出す方法 rails
https://qiita.com/tanaka-yu3/items/741711bd743b80eda51a
- 投稿日:2020-06-25T13:49:11+09:00
railsのlink
文字でリンクする
1.URLでリンクする場合
<%= link_to “次へ”, “http://www.XXXXXXXXXXXX” %>2.パスでリンクする場合
<%= link_to "次へ", "root_path" %>ちなみにパスの確認方法
rake routesと打って一番左の列に _path をつけたものがパス。
画像でリンクする
<%= link_to image_tag("画像名", class:"クラス名"), パス %>
- 投稿日:2020-06-25T13:28:31+09:00
gem
gem
gemfileに使いたいgemを記載する。
その際group :development, :test do group :development do group :test doのようなグループ分けがされているが、これはgemがどの環境において使われるかによって分類する。
gemはデータ量が小さくないので、本番環境では使用しないgemなどをこれらに入れる。:development
は開発環境のみで使用するgem:test
はテストにのみ使用するgem:development, :test
は開発環境及びテストで使用するgem本番環境でも使用するgemはこれらのグループの外側に入れる。
gemをgemfileに記載したらコンソールで
bundle installするのがお決まり。
- 投稿日:2020-06-25T13:14:50+09:00
最初メモ
- 投稿日:2020-06-25T10:40:33+09:00
Railsで投稿編集時に予め所属カテゴリにチェックをつける方法
多対多の関係のPostとCategoryをもつテーブルに置いて、Post編集時に既存のカテゴリに予めチェックボックスをつける方法。
form_with model: @post
の形式を使わないと{checked:}
オプションを使えないので少しハマった。前提:多対多のテーブル構成を実現する
以下を参考にテーブル構成してる前提です。ただし投稿の
title
は本記事ではname
になってます。collection_check_boxesの引数に
{checked:}
オプションを追加前段の多対多のテーブルを作成している前提だと、
@post.category_ids
で所属カテゴリを配列で取得できるらしい。それに.map(&:to_param)
してやることでチェックが付く。この&:to_param
というのはいつも固定で、@post
やcategory_ids
のようにテーブルやモデルの名称によって変わるものではない。app/views/posts/edit.html.erb<%= f.label :category, 'カテゴリ' %> <%= f.collection_check_boxes(:category_ids, Category.all, :id, :name, { checked: @post.category_ids.map(&:to_param) }) do |category| %> <%= category.label do %> <%= category.check_box %> <%= category.text %> <% end %> <% end %>もし
form_with model: @post
で「undefined method 'post_path'」とエラーが出る時
form_with model: @post, url: posts_create_path do
みたいな書き方をしていると{checked:}
オプションは使えない。以下の回答のコメント欄にあるようにresouces
を使わないといけない。
https://teratail.com/questions/200474本題:最終的なコード
routes.rbRails.application.routes.draw do resources :posts, only: [:new, :create, :edit, :update] endposts_controller.rbclass PostsController < ApplicationController def new @post = Post.new end def create @post = Post.create(post_params) redirect_to('/posts/index') end def show @post = Post.find(params[:id]) end def edit @post = Post.find(params[:id]) end def update @post = Post.find(params[:id]).update(post_params) redirect_to("/posts/index") end private def post_params params.require(:post).permit(:name, category_ids: []) end endapp/views/posts/edit.html.erb<div class="main posts-index"> <div class="container"> <%= form_with model: @post do |f| %> <p> <%= f.label :name, 'name'%> <%= f.text_field :name %> </p> <p> <%= f.label :category, 'カテゴリ' %> <%= f.collection_check_boxes(:category_ids, Category.all, :id, :name, { checked: @post.category_ids.map(&:to_param) }) do |category| %> <%= category.label do %> <%= category.check_box %> <%= category.text %> <% end %> <% end %> </p> <%= f.submit '変更を保存' %> <% end %> </div> </div>その他
Railsはマイグレーションファイルの生成や
db:migrate
を少しでもミスると、特に本番デプロイ時にDBがおかしくなったりするから気をつけてね。一度でもdb:migrate
したら、もうそのマイグレーションファイルは使えないし、schemaを直接書き換えたりしてもダメだよ。こちらも参考になりそう?
【Rails】form_with/form_forについて【入門】
- 投稿日:2020-06-25T10:06:19+09:00
本番環境の設定ファイルをふっ飛ばした話
はじめに
Qiita夏祭り企画参加の記事です。
テーマページ②:システム開発における過去の失敗と乗り越えた方法について共有しよう!
こちらのテーマに参加します。アプリケーション詳細
Rails製の本番稼働しているアプリがありました。
そのアプリは.env
ファイルに本番で使っている環境変数が定義されていました。
.env
ファイルは本番の接続情報を持っているためgit管理対象外となっていました。
ローカルに環境構築をする用に.env.example
はgit管理で用意されていました。中身は以下のようなもの
.env.example# Railsの設定 RAILS_ENV=development # Bitbucket APIの設定 BITBUCKET_KEY=XXXXXXXXXXXXXXXXXX BITBUCKET_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXBitbucketと連携するためにAPIキーが設定されていました。
環境構築時には以下コマンドを実行してください、というのがREADMEに書いてありました。
cp .env.example .env
.env.example
をコピーして.env
ファイルを作成し任意のAPIキーに上書きしてテストする、というようなもの。何をしたか
本番環境の設定ファイルをふっ飛ばしました。
本番デプロイ時に寝ぼけていたのか
cp .env.example .env
これを実行し本番の設定ファイルがexampleに置き換わり、本番で設定していたAPIキーが分からなくなりました。
デプロイ作業中は気付かず、デプロイした部分の動作確認をして「なんか動かないなー」となってハッと気が付き、血の気が引きました。
このアプリケーションは元々自分が作ったものではなく、どのユーザーの何のAPIキーを使っていたのかも知りませんでした。
当時本アプリを作った担当者はもう退職済みで確認も取れない状況でした。解決方法
過去の情報を必死に引っ張り出しましたがどこにも情報は残っていませんでした。
必死に調査したところ、うまく動いているところと動いていないところがあることが発覚。
本アプリはwebとバッチに分かれており、バッチの方のみ再起動したため、バッチの方は上書きしてしまった.env
を参照しwebの方は上書き前の.env
を参照しているようでした。
webのソースの方にログを吐く処理を追加しダンプp ENV['BITBUCKET_KEY'] p ENV['BITBUCKET_SECRET']そうしたところ前の
.env
の設定値が出力された。
私は急いでそれをメモし.env
ファイルに適用、バッチの再起動を実施。
無事にバッチも動き出しました。おわりに
教訓: 寝ぼけながらデプロイしない
やってしまったとしても焦らず解決策を探す。
今回の場合は仮に前の値が見つからなかったとしても、新しくbotユーザーを作成しそのユーザーのAPIキーを設定すればうまくいくだろうし、必ずしも復旧させる必要はなかったかもしれません。
肝が冷えたお話でした。
- 投稿日:2020-06-25T07:01:13+09:00
インクリメンタルサーチ
はじめに・目的
- search controllerのhtml viewでの検索機能だと、ワード全て入力して検索しないといけない。
- jsonを使ったインクリメンタルサーチだと、非同期で検索可能。
- テーブル内で検索が頻繁に行われるカラムにインデックスを設定することで検索の高速化を図る。
- 今回はtweetsテーブルのtextカラムにインデックスを貼ることで、データの検索を高速化する。
terminal$ rails g migration AddIndexToTweetsマイグレーションファイルclass AddIndexToTweets < ActiveRecord::Migration def change add_index :tweets, :text, length: 32 end end→migrate実行
1.ルーティングなどAPI側の準備
Formatごとの条件分岐
app/controlers/tweets_controller.rbdef search @tweets = Tweet.search(params[:keyword]) respond_to do |format| format.html format.json end end #投稿情報を取得したら、jbuilderを使ってJavaScript側に返す。 #検索結果は、複数の投稿情報を表示させます。 #そのため、複数の投稿情報が格納された配列を返すようなjbuilderの記述にする必要がありますjson.jbuilderの作成
app/views/tweets/search.json.jbuilderjson.array! @tweets do |tweet| json.id tweet.id json.text tweet.text json.image tweet.image json.user_id tweet.user_id json.nickname tweet.user.nickname json.user_sign_in current_user endJSON形式のデータを配列で返したい場合は、上記のように
array!
を使用。2. テキストフィールドを作成
views/tweets/index.html.erb<%= form_with(url: search_tweets_path, local: true, method: :get, class: "search-form") do |form| %> <%= form.text_field :keyword, placeholder: "投稿を検索する", class: "search-input" %> <%= form.submit "検索", class: "search-btn" %> <% end %>3.テキストフィールドに文字入力するたびに、イベント発火
app/assets/javascripts/search.js$(function() { $(".search-input").on("keyup", function() { var input = $(".search-input").val(); }); }); //キーを離したら処理をさせたいときはkeyupメソッドを使用4.イベント時に非同期通信できるよう$.ajaxメソッドの記載
app/assets/javascripts/search.js$(function() { $(".search-input").on("keyup", function() { var input = $(".search-input").val(); $.ajax({ type: 'GET', //HTTPメソッドはGET url: '/tweets/search', //rails routesで確認 data: { keyword: input }, dataType: 'json' }) }); });5.非同期通信の結果を得て、HTMLを作成
app/assets/javascripts/search.js.done(function(tweets) { search_list.empty(); if (tweets.length !== 0) { //tweetsの数が0でない時、 tweets.forEach(function(tweet){ //forEachメソッド appendTweet(tweet); }); } else { appendErrMsgToHTML("一致するツイートがありません"); } }) .fail(function() { //error時のaleart実装 alert('error'); }); }); });
- forEachは、与えられた関数を配列に含まれる各要素に対して一度ずつ呼び出します
search.js変数・メソッド定義var search_list = $(".contents.row"); function appendTweet(tweet) { if(tweet.user_sign_in && tweet.user_sign_in.id == tweet.user_id){ var current_user = `<li> <a href="/tweets/${tweet.id}/edit" data-method="get" >編集</a> </li> <li> <a href="/tweets/${tweet.id}" data-method="delete" >削除</a> </li>` } else { var current_user = "" } var html = `<div class="content_post" style="background-image: url(${tweet.image});"> <div class="more"> <span><img src="/assets/arrow_top.png"></span> <ul class="more_list"> <li> <a href="/tweets/${tweet.id}" data-method="get" >詳細</a> </li> ${current_user} </ul> </div> <p>${tweet.text}</p><br> <span class="name"> <a href="/users/${tweet.user_id}"> <span>投稿者</span>${tweet.nickname} </a> </span> </div>` search_list.append(html); } function appendErrMsgToHTML(msg) { var html = `<div class='name'>${ msg }</div>` search_list.append(html); }