- 投稿日:2020-03-19T23:40:08+09:00
【13日目】Ruby(配列,ハッシュ)
はじめに
こんばんは。
Ruby2日目です。
平日の進捗はゆっくりなので、
休みに盛り返していきます。
では、本日のまとめをしたいと思います。本日の学び
- progate Ruby2
Ruby
配列
languages = ["日本語","英語","スペイン語"] //インデックスは0,1,2の順 puts languages[1]each文
languages = ["日本語", "英語", "スペイン語"] languages.each do |language| #インデックスをそれぞれlanguageとする puts "#{language}を話せます" #回答はインデックスの数だけ #この中の変数はこの中でしか使えないので注意 end #忘れないようにハッシュ
exam = {"subject"=>"Math","score"=>80 } #複数の値をまとめて管理する。{}を使う。 puts exam["subject"] #examのsubjectのみ exams = [ {subject: "Math", score: 80}, {subject: "Science", score: 55} ] puts exams[1][:score]シンボル
exam = {:subject => :Math, :score => 80} #"の置き換え exam={subject: "Math", score: 80} puts exam[:score]ifハッシュ
exam = {subject: "Math"} if exam[:score] puts "#{exam[:subject]}の結果は#{exam[:score]}点です" else puts "#{exam[:subject]}の結果は分かりません" #値が無い場合falseとし、要素を入れない end所感
Rubyは上から順に辿ってく感じである気がします。
後でコードを読み返した時に分かりやすい印象を受けました。明日からの3連休、頑張って平日のスローペースを取り返したいです。
- 投稿日:2020-03-19T23:39:20+09:00
[HowTo]ActiveStorage/アバター画像を登録&表示
先日、Active Storageを使用してアバター登録機能を実装しましたので、備忘録として以下に手順などをまとめておきます!
皆様の開発に少しでも役立てていただければ幸いです。Active Storageとは
Active Storageとは、Rails 5.2以降に追加された機能で、ファイルのアップロードを可能にします。
似たような機能でCarrierWaveというものもございますが、こちらは過去に記事にしていたので、
今回はActive Storageを使用することにしました。
https://qiita.com/Tatsu88/items/66374abda7245a006ea0Active Storageの特徴
ActiveStorageはactive_storage_attachmentsとactive_storage_blobsの2つのテーブルを作成します。
アップロードした情報はこれらのテーブルに格納され、モデルと関連づける必要があります。完成イメージ
今回はマイページのアバター実装を目指します。
まず、アバター情報がないときは以下のイメージとなります。マイページ(アバターなし)
登録画面
上記にてアバター情報を登録するとマイページに表示できるようにします。
下準備
ImageMagickとmini_magickのインストール
Active Storageで画像を加工してから(サイズや色など)アップロードするには別のツールをインストールする必要があります。
ImageMagickという画像変換ツールと、それをRailsから使うためのmini_magickというgemをインストールしましょう。ImageMagickのインストール
ImageMagickは、コマンドラインから簡単に画像の保存形式の変更などが行えるツールです。
ターミナルで下記のコマンドを実行してください。ターミナル$ brew install imagemagickmini_magickのインストール
続いて、mini_magickをインストールしましょう。
mini_magickは、Gemの一種なので、Gemfileに記載します。Gemfilegem 'mini_magick'ターミナル$ bundle install #gemを追加したので、必要に応じてrails sは再接続しましょうActive Storageのインストール
上記にて下準備ができましたので、早速Active Storageをインストールしましょう。
ターミナル$ rails active_storage:install #上記で作成したマイグレーションファイルをマイグレートしましょう。(編集は不要です) $ rails db:migrate上記コマンドにて、以下のテーブルが作成され、アップロードした情報はこちらに格納されます。
- active_storage_attachments
- active_storage_blobs関連モデルの編集
上記にてActive Storageの準備ができましたので、続いて関連するモデルを編集しましょう。
今回は"User"モデルに対して、アップロードされた画像情報を"avatar"として紐付けます。/models/user.rbhas_one_attached :avatarview:登録画面
今回は、form_withを使用して情報を登録します。
先ほどモデルに記載した情報をベースに記載します。view(抜粋)= form_with model: @user, url: profile_update_user_path ,method: :patch, local:true do |f| .form-group = f.label :プロフィール写真 = f.file_field :avatar #既に画像設定されている場合は、その内容を削除します。 -if @user.avatar.attached? =@user.avatar.purge .form-group %p.form-group__text--center = f.submit '変更する', class: "btn-default btn-red"view:登録内容表示画面
上記記述にて登録した内容を表示するviewを作成します。
ポイントとしては、アバター画像がある場合とない場合で表示する画像を分けてます。
アバター画像の有無は".attached?"メソッドを使用してます。
nil?やblank?やpresent?を使うとうまくいかないので、ご注意ください。view(抜粋).mypage_top_container .mypage_top_container_avator .mypage_top_container_avator_main -if @user.avatar.attached? =image_tag @user.avatar, class:"avatar" -else =image_tag ("noimage.png"),class:"avatar"以上で設定したアバター画像を表示することができます!
その他、コントローラやルーティングなど準備は必要となりますが、各自設定によると思われますので、
今回は割愛させていただきます。参照
Active Storage の概要
https://railsguides.jp/active_storage_overview.html【Ruby入門】真偽判定present?の使い方をわかりやすく解説
https://www.sejuku.net/blog/66030[Rails5.2]ActiveStorageの仕組み(図あり)と使ってみてわかったこと
https://qiita.com/eightfoursix/items/a47ce1bd945582f5d808【Rails】image_tagの使い方を徹底解説!
https://pikawaka.com/rails/image_tagActiveStorage で画像を複数枚削除する方法
https://h-piiice16.hatenablog.com/entry/2018/09/24/141510Active Strageを使用してユーザーのアバターを登録、表示する
https://re-engines.com/2018/03/12/active-strage%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E3%82%A2%E3%83%90%E3%82%BF%E3%83%BC%E3%82%92%E7%99%BB%E9%8C%B2%E3%80%81%E8%A1%A8%E7%A4%BA/以上となります。最後までご覧いただき、ありがとうございました!
今後も学習した事項に関してQiitaに投稿していきますので、よろしくお願いします!
記述に何か誤りなどございましたら、お手数ですが、ご連絡いただけますと幸いです。
- 投稿日:2020-03-19T23:31:15+09:00
インクリメンタルサーチで追加済みユーザーが検索されないようにする
目的
チャットアプリのグループメンバー追加ページを以下の仕様で作成する。
- インクリメンタルサーチでメンバー検索をして登録リストに表示
- 登録リストに表示されたメンバーを登録ボタンで追加リストに登録
- 登録されたメンバーは登録リストに表示されない問題点
登録されたメンバーが登録リストに表示されてしまう。
考え方
検索されたメンバーのIDが追加リストに登録されたメンバーのIDと重複しない場合のみ表示させれば良い。
コード
before.jsusers.forEach(function (user) { if (user.id) { addUser(user); } })after.jsusers.forEach(function (user) { let idNum = document.getElementById(user.id); if (user.id && !idNum) { addUser(user); } })
- 投稿日:2020-03-19T22:30:03+09:00
Railsで、どちらか一方のカラムを入力必須(二者択一)にするバリデーション
はじめに
Ruby on Rails で どちらか一方のカラムを入力必須にするバリデーションについて書きます。
具体的な例をあげると、ユーザーモデルの
phone
、どちらか片方だけに必ず値が入るようにバリデーションします。両方に値が入っている場合もNGです。要件に合わなかったバリデーション
ググって下記のようなバリデーションを見つけましたが、両方入力した場合にバリデーションを通ってしまうので、要件には合いません。
app/models/user.rbclass User < ApplicationRecord # phoneが空ならば、emailを必須にする validates :email, presence: true, unless: :phone? # emailが空ならば、phoneを必須にする validates :phone, presence: true, unless: :email? endUser.create!(name: "たなか", email: "test@example.com", phone: "08011112222") => #<User id: 1, name: "たなか", email: "tanaka@example.com", phone: "08011112222", created_at: "2020-03-19 12:29:20", updated_at: "2020-03-19 12:29:20">要件にあったバリデーション
要件を満たすために、次のカスタムバリデーションを作成しました。
app/models/user.rbclass User < ApplicationRecord validate :required_either_email_or_phone private def required_either_email_or_phone # 演算子 ^ で排他的論理和(XOR)にしています # emailかphoneのどちらかの値があれば true # email、phoneどちらも入力されている場合や入力されていない場合は false return if email.present? ^ phone.present? errors.add(:base, 'メールアドレスまたは電話番号のどちらか一方を入力してください') end endUser.create!(name: "たなか", email: "tanaka@example.com", phone: "08011112222") # => ActiveRecord::RecordInvalid (バリデーションに失敗しました: emailまたはphoneのどちらか一方を入力してください) User.create!(name: "たなか", email: nil, phone: nil) # => ActiveRecord::RecordInvalid (バリデーションに失敗しました: emailまたはphoneのどちらか一方を入力してください) User.create!(name: "たなか", email: "tanaka@example.com", phone: nil) # => <User id: 2, name: "たなか", email: "tanaka@example.com", phone: nil, created_at: "2020-03-19 13:06:55", updated_at: "2020-03-19 13:06:55">おわり
普段は論理和
||
演算子 か論理積&&
演算子 ばかりで、^
演算子は使わないので、上記のコードを思いつくまでに時間をかけてしまいました…!
- 投稿日:2020-03-19T21:27:47+09:00
EC2サーバで生成した公開キーはどこからどこまでなのか
- 投稿日:2020-03-19T19:58:27+09:00
初めてのbootstrap導入(rails)
はじめに
bootstrapを導入する時に手間取ってしまったので、初めて触ってみる人でもわかりやすく、導入手順を一からおさらいします超初級編です
bootstrapは簡単にgridレイアウトを実現できるので、使えるようになると便利です① Gemfileの末尾にbootstrapを追加
Gemfilegem 'bootstrap'今回はバージョン指定はしません。
この時、compass-railsというgemが追加されてあるとエラーを吐いてしまうので、なくて問題ないようなら削除します。② gemの更新
terminal$ bundle install③ application.cssにbootstrapを導入
app>assets>stylesheet>application.css
application.css@import "bootstrap";application.cssをapplication.scssに名前変更
④ application.jsにもbootstrapを適用
app>assets>javascripts>application.js
application.js//= require bootstrap⑤ bootstrapを挿入
bootstrapから、好きなデザインを探し、適応させたいビューファイルに挿入します。
bootstrapトップページから、ヘッダーのDocumentation->左にあるCommponentsから探します。e.g.) 今回は、headerにNavbarを使います。
app>views>layouts>application.html.erb
application.html.erb<header> ここにコピーしたコードを貼り付け </header>これで$ rails sでサーバーを起動させて該当ページを表示させると、下のようにbootstrapが適用されます。
後はエディタのbootstrapをコピーした部分のリンクや表示させたい文字などを調節して完成です!やったね!
- 投稿日:2020-03-19T18:28:08+09:00
スクリプト言語 KINX/ライブラリ(File/Directory)
ライブラリ(File/Directory)
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」でお届けしているスクリプト言語 Kinx。前回の記事で プレビュー・リリースしたぜ と勇み足ぎみに突っ走ったが、マニュアルが整っていないので、やはりなかなか使いづらいに違いない。現時点で参考になるのは以下しかないし、英語なので。
- Quick Reference Guide
- Kinx Specification
- 初回紹介記事 からの各種リンク
- 一応、ここは日本語。
そこでだ、若旦那。
少しだけマニュアル代わりになるように、簡易説明をここに記すことにしましたよ。今回は File と Directory。一番実用的な感じがしたので。
重要:
v0.1.0 ではファイル系のインタフェースが不完全だったので、急遽 v0.2.0 を用意しました。下記の内容は v0.2.0 のものです。v0.1.0 では動作しないものが一部あります。
また、標準入力をサポートしました。リリース内容は下記を参照してください。
* リリース・リストライブラリ
File クラス
File クラスはその名の通りファイルの読み書きをするクラスで、静的メソッドを持つ。また、
new File(filename, attr)
として個別のファイル・インスタンスを作成することもできる。静的メソッド
File クラスの静的メソッドは、以下の通り。
メソッド 内容 復帰値(型) 引数 意味 File.load(path)
ファイル内容をテキスト形式で一括読込み String path: String 中身を読み込むファイルパス File.mkdir(path)
ディレクトリの作成 1: 成功 path: String 作成するディレクトリ・パス File.rename(oldname, newname)
ファイルパスの変更 1: 成功 oldname: String 変更前のファイルパス newname: String 変更後のファイルパス File.unlink(path)
ファイルの削除 1: 成功 path: String 削除するファイルパス File.exists(path)
ファイルの存在確認 1: 存在する path: String 確認するファイルパス File.isDirectory(path)
ディレクトリ名かどうかの確認 1: ディレクトリである path: String 確認するファイルパス File.isSymlink(path)
シンボリックリンクかどうかの確認 1: シンボリックリンクである path: String 確認するファイルパス File.filesize(path)
ファイルサイズの取得 Integer path: String 確認するファイルパス File.filedate(path)
ファイル日付の取得 { modified, accessed, creation }
path: String 確認するファイルパス File.setFiledate(path, obj)
ファイル日付の設定 path: String 確認するファイルパス obj: Object { modified, accessed, creation }
File インスタンス
File インスタンスは
new
で作る。サンプルは以下の通り。var f = new File(filename, attr);パラメータは以下の 2 つ。
パラメータ 取りうる値 意味 filename 文字列 ファイル名 attr 以下の値の論理和 オープン属性 File.READ
読込可能 File.WRITE
書込可能 File.NEW
新規作成モード File.TEXT
テキストモード File.BINARY
バイナリモード
- オープン属性は以下のような感じで指定する。
File.READ|File.WRITE
... 追記モードで読み書き可能File.READ|File.WRITE|File.NEW
... 新規作成モードで読み書き可能File.READ|File.TEXT
... テキストモードで読み込み専用File インスタンスのメソッドは以下の通り。すみません、
peek
、getch
、putch
は v0.1.0 に含まれていません。。。
メソッド 内容 復帰値(型) 引数 意味 f.load()
ファイルの中身を一括読み込み String f.close()
ファイルをクローズ f.readLine()
一行読み込み String, 0: EOF f.peek(ms)
入力があるか確認 1: 存在する、0: 存在しない ms: Integer タイムアウト(ミリ秒) f.getch()
1 文字入力 Integer (取得文字コード) f.putch(ch)
1 文字出力 ch: Integer 出力文字コード f.print(...args)
改行文字なしで出力 出力文字数: Integer ...args 表示する要素(可変引数) f.println(...args)
改行文字付きで出力 出力文字数: Integer ...args 表示する要素(可変引数) File.open
個別に
new
した場合はclose
しなければならない(GC されたら勝手にクローズ自体はされる)が、スコープを決めて自動的にクローズさせたい場合はFile.open
を使うのがオススメ。スコープを抜けるとその場で自動的にクローズされる。こんな感じ。File.open("README.md", File.READ, &(f) => { var l, n = 0; while ((l = f.readLine()).isString) { System.println("%4d: %s" % (++n) % l); } });
File.open
の内容としては、意味的には次のと概ね同等。function FileOpen(filename, attr, func) { var f = new File(filename, attr); try { return func(f); } finally { f.close(); } }Directory
ディレクトリをトラバースするために使う。サブディレクトリを見つけた時に再帰的に潜っていく場合は
recursiveWalk
、潜っていかない場合はwalk
を使う。Directory.walk
Kinx のリポジトリ・フォルダで以下を実行してみるとなんとなくわかるかも("src" ディレクトリがあるので動作する、という意味。存在するディレクトリ名にすればどこでも OK)。
Directory.walk("src", &(name) => { System.println(name); });Directory.recursiveWalk
次のように実行すると違いがわかるはず("src" 配下にサブディレクトリがある前提)。
Directory.recursiveWalk("src", &(name) => { System.println(name); });おわりに
先日、昔のツェッペリンのインタビューを読んでみて、新しい何か、自分たちがやりたい何か、をガレージ・レベルからスタートさせてやっていく、ってのは改めて ロックだねえ、と感慨に耽っていました。ビッグになったロックスターたちも、最初は こういうのやりたいんだよ とガレージやクラブからスタートさせてる訳です。夢と希望を忍ばせて。
今あるものに満足せずに、また、今現在提供されているものに満足行かないようなら、文句を言うのではなく自分の手で実現させてしまうのが良いよね。そのアティテュードこそがまさに ロックンロール。
まだまだ転がり続けようぜ、相棒。
で、最後はいつものおねだりの時間です。
- 最初の動機は スクリプト言語 KINX(ご紹介) を参照してください(もし宜しければ「
いいねLGTM」ボタンをポチっと)。- リポジトリは ここ(https://github.com/Kray-G/kinx) です。こちらももし宜しければ★をポチっと。
- 投稿日:2020-03-19T18:20:43+09:00
RailsのformにAjaxを実装する前提
RailsにjQueryを使ったAjaxを適用するために色々調べました。
個人的な備忘録として残します。configを設定
config/application.rbrequire File.expand_path('../boot', __FILE__) module SampleApp class Application < Rails::Application config.action_view.embed_authenticity_token_in_remote_forms = true # 追加 end endコントローラーの変更
class HogesController < ApplicationController def hoge respond_to do |format| format.html redirect_to hoge_path format.js # ※下 end end end※ renderで指定しなければ
アクション名.js.erb
を探すテンプレートの変更
form_with
を使っている場合(推奨)
remote
はデフォルトでtrueのでやることなし
(falseにしたい場合はlocal: true
を追加)app/view/hoges/hoge.html.erb<div id="ajax-test"> <%= form_with ... do |f| %> <%= f.submit "hogehoge" %> <% end %> </div>
form_for,
form_tag
を使っている場合、オプションに
remote: true
を付ける。app/view/hoges/hoge.html.erb<div id="ajax-test"> <%= form_for ..., remote: true do |f| %> <%= f.submit "hogehoge" %> <% end %> </div>コントローラーで
render
しなかった場合、以下の点に注意してファイル.js.erb
を追加
・適用したいテンプレートと同じ場所に配置
・ファイル名はコントローラーのアクション名と同じ名前に設定app/view/hoges/hoge.js.erb$("#ajax-test").html("<%= 'さあ、遠慮なく私をhogeりなさい!' %>");記述はjQueryで。
.html("...");
の部分を
.html("<%= escape_javascript(render('hoges/hoge')) %>");
.html("<%= j ( render('hoges/hoge') ) %>");
でも可
などとすると色々できる。
- 投稿日:2020-03-19T14:42:42+09:00
Ruby on Rails チュートリアル学習記録 第6章
第4、5章については特に書く内容がなかったため学習記録は付けませんでした
6.1
特になし
6.2
特になし
6.3
heroku run rails db:migrate
をbash: heroku: command not found
というエラーメッセージ。
3章の時と同じ方法で解決
nvm install node
npm install -g heroku-cli
を実行後、あらためてheroku run rails db:migrate
を実行6.4
特になし
- 投稿日:2020-03-19T14:30:48+09:00
Rubyの例外処理まとめ
そもそも例外とは?
プログラム実行中に発生したエラーの意。
例外処理を記述しないと、例外発生時点でプログラムが停止してしまい、それ以降に記述してあるコードが読み込まれない。
Rubyで例外を補足するためにはrescue
メソッドを用いる。例外の種類
Ruby公式リファレンスを参照。
begin~rescueメソッド
例)「1/0」の箇所で、整数は0では割れないため、「ZeroDivisionError」という例外が発生。
begin 1/0 rescue => e puts e end #=> divided by 0eには例外オブジェクト(ZeroDivisionErrorなど)が代入されるので、それら例外オブジェクトに実装されている基本的なメソッドを使用することができる。
- class : 例外の種類
- message : 例外のメッセージ
- backtrace : 例外発生の位置情報begin 1/0 rescue StandardError => e puts e puts e.class puts e.class.superclass puts e.message end #=> divided by 0 #=> ZeroDivisionError #=> StandardError #=> divided by 0応用メソッド(ensure/retry/raise/File.open)
ensure:例外の有無に関わらず実行される
begin 1/0 rescue => e puts e ensure puts "ensure" end #=> ensureretry:beginからの実行をもう一度やり直す
count = 0 begin 1/0 rescue p count += 1 retry if count < 3 puts "failed" end #=> 1 #=> 2 #=> 3 #=> failedraise:意図的に例外を起こす
begin raise rescue p "例外です" end #=> 例外です
- 投稿日:2020-03-19T13:21:49+09:00
ウェブサービスの主な機能について
- 投稿日:2020-03-19T11:52:40+09:00
【Rails/Ruby】クラスメソッドとインスタンスメソッドの使い分け
「クラスメソッドとインスタンスメソッドの使い分けについて教えてください」
って前に聞かれてちょっと困ったことを思い出したのでまとめてみました~???※クラス・インスタンスの概念の説明やクラスメソッド・インスタンスメソッドの詳しい説明は端折ってます~!
クラスメソッド
・クラスに対して使う
例:newメソッド/など# インスタンスの生成 Animals.new・DBからデータを取得したり保存するときに使う
例:allメソッド/findメソッド/createメソッドなど# 引数に一致するデータをDBから取得する User.find(1)・外部ファイルやサイトからデータを取得する(データを取得し、インスタンスを作成する)ときに使う
例:スクレイピングなど・全体で扱うべき情報を扱うときに使う
例:投稿の総数などインスタンスメソッド
・生成した個々のインスタンス(投稿1つ1つ、ユーザー1人1人など)に対して使う
例:update/destroy/eachなど# userにインスタンスを代入 user = User.find(1) # userに代入したデータを削除する user.destroy最後に
個人的にわかりやすいと思ったクラスとインスタンスの説明で終わります~!
クラス = 野菜という大枠 インスタンス = ニンジン・オクラ・ブロッコリーなど細かな種類クラスとインスタンスの概念って理解するのってやっぱり難しいですね?
- 投稿日:2020-03-19T11:03:55+09:00
Hashの先頭からn個をとりだす
データを抽出してchartkickに渡すHashに対し、先頭n件を抽出したかった。
helperに以下のメソッドを作成。def chart_limit(hash, limit=5) # Hash[*hash.to_a.shift(limit).flatten!] # コメントを受けて以下に変更。 hash.take(limit).to_h end利用例hash = {"男性40代"=>13, "女性40代"=>6, "女性30代"=>5, "男性60代"=>4, "男性30代"=>4} p chart_limit(hash, 3) #=> {"男性40代"=>13, "女性40代"=>6, "女性30代"=>5}ruby 2.6.5で確認済み。
参考
- 投稿日:2020-03-19T10:01:34+09:00
SQLインジェクションを回避して、SQL内のカラムを動的に変える
概要
①飲食店クラスがあって、ランチの時間帯とディナーの時間帯を絞り込むメソッドがある
②内部的には、引数に始まりの時間と終わりの時間を受け取って、その条件に合うレコードを取得する
③両者はロジックがほぼ一緒で、違うのはwhere句内のカラムだけ
④同じロジックは書きたくないので、なるべく共通化させたい!# 飲食店クラス class Restaurant < ApplicationRecord # 飲食店のランチの時間を絞り込むメソッド scope :where_by_between_lunch_time, lambda { |start_date, end_date| if start_date.present? && end_date.present? where('lunch_time BETWEEN ? AND ?', start_date, end_date) elsif start_date.present? where('lunch_time >= :date', date: start_date) elsif end_date.present? where('lunch_time <= :date', date: end_date) end } # 飲食店のディナーの時間を絞り込むメソッド scope :where_by_between_dinner_time, lambda { |start_date, end_date| if start_date.present? && end_date.present? where('dinner_time BETWEEN ? AND ?', start_date, end_date) elsif start_date.present? where('dinner_time >= :date', date: start_date) elsif end_date.present? where('dinner_time <= :date', date: end_date) end } end対策① 引数の検証を行うように
まず、調べていくとカラムを動的に変えようとするとSQLインジェクションの恐れがあることに気付く。
(SQLインジェクションがわからない方はこちらを参考に)なのでSQLインジェクションにならないように、最初はこの記事を参考に引数の検証を行うように変更!
# 飲食店クラス class Restaurant < ApplicationRecord ALLOWED_COLUMNS = %w(lunch_time dinner_time).freeze scope :where_by_between_date, lambda { |column, start_date, end_date| # 定数で予め受け取る想定のカラム名を定義して、それ以外が来たらエラー unless text.in?(ALLOWED_COLUMNS) raise ArgumentError, "Invalid argument: #{column}" end if start_date.present? && end_date.present? where("#{column} BETWEEN ? AND ?", start_date, end_date) elsif start_date.present? where("#{column} >= :date", date: start_date) elsif end_date.present? where("#{column} <= :date", date: end_date) end } end確かに、これだと良さそう・・・
しかし、これにしてもBrakemanで怒られてしまう。。。
(Brakemanは、簡単に言うとRailsアプリケーション内のセキュリティをチェックしてくれるGemです)対策② サニタイズ処理をする
そんな中、Railsのドキュメントを見ていると
quote_column_name
というメソッドを発見!
使えそう!!ふむふむ。SQLインジェクションにならないようにサニタイズをしてくれるメソッドっぽい。
# 飲食店クラス class Restaurant < ApplicationRecord scope :where_by_between_date, lambda { |column, start_date, end_date| # sqlインジェクションにならないようにサニタイズ処理をする sanitized_column = ActiveRecord::Base.connection.quote_column_name(column) if start_date.present? && end_date.present? where("#{sanitized_column} BETWEEN ? AND ?", start_date, end_date) elsif start_date.present? where("#{sanitized_column} >= :date", date: start_date) elsif end_date.present? where("#{sanitized_column} <= :date", date: end_date) end } endこれだとBrakemanで怒られなくなったし、カラムを動的に変えることができるようになった!!
リファクタ
ここからはリファクタ対応。
元々はこの
where_by_between_date
にカラム名を第一引数に渡す想定だったけど、
今後呼び出される側のロジックが変更される可能性も想定して、抽象scopeに変更。# 飲食店クラス class Restaurant < ApplicationRecord # 抽象スコープ scope :where_by_between_date, lambda { |column, start_date, end_date| # sqlインジェクションにならないようにサニタイズ処理をする sanitized_column = ActiveRecord::Base.connection.quote_column_name(column) if start_date.present? && end_date.present? where("#{sanitized_column} BETWEEN ? AND ?", start_date, end_date) elsif start_date.present? where("#{sanitized_column} >= :date", date: start_date) elsif end_date.present? where("#{sanitized_column} <= :date", date: end_date) end } # 下記スコープで抽象スコープを呼び出す形に scope :where_by_between_lunch_time, lambda { |start_date, end_date| where_by_between_date(:lunch_time, start_date, end_date) } # 下記スコープで抽象スコープを呼び出す形に scope :where_by_between_dinner_time, lambda { |start_date, end_date| where_by_between_date(:dinner_time, start_date, end_date) } endこれだとメソッド名も直感的なのでよりわかりやすくなったし、
なにより今後の変更にも強くなった気がする!追記
対策③ ActiveRecordのメソッドを使う
ご指摘ありがとうございました!
よく考えれば、そもそも生SQLに埋め込まないでActiveRecordのメソッドを使えば問題なかったですね
難しく考え過ぎていました。。。
(まあ、でもRailsのサニタイズ処理に関して勉強になったのでヨシ)
# 飲食店クラス class Restaurant < ApplicationRecord START_DATE_INFINITY = '1000-01-01' END_DATE_INFINITY = '3000-01-01' # 対象のテーブルで不明なcolumnにはUndefinedColumnが出る scope :between_date, lambda { |column, start_date, end_date| if start_date.present? && end_date.present? where(column => start_date..end_date) elsif start_date.present? # end_dateが無いなら、遠い未来までの範囲 where(column => start_date..END_DATE_INFINITY) elsif end_date.present? # start_dateが無いなら、遠い過去までの範囲 where(column => START_DATE_INFINITY..end_date) end } endおまけ
現在、
Float::INFINITY
は範囲指定の終わりにしか使用できないんですよね。(Rubyのバグ)ですが、、、issueにこのように書いてありました!
Ruby 2.6 supports endless range, and ruby 2.7 will support beginless range.
つまり今後リリースされるであろう、Ruby2.7だと始まりに対してもInfinityを使えるようになるみたいです!
その際はこんな感じで書けますね!
# 飲食店クラス class Restaurant < ApplicationRecord scope :between_date, lambda { |column, start_date, end_date| if start_date.present? && end_date.present? where(column => start_date..end_date) elsif start_date.present? where(column => start_date.to_time..Float::INFINITY) elsif end_date.present? # 2.7以降使用できる where(column => -Float::INFINITY..end_date.to_time) end } endこっちの方が個人的には綺麗に見えるけど、可読性は微妙かな・・・
[参考記事]
https://qiita.com/jnchito/items/e3a144b07f578cda5ee2
https://www.kagoya.jp/howto/network/sql-injection/
https://api.rubyonrails.org/v4.2/classes/ActiveRecord/ConnectionAdapters/Quoting.html
https://bugs.ruby-lang.org/issues/12961
- 投稿日:2020-03-19T05:48:06+09:00
bootstrap3から4への移行方法について (Rails5)
今回はbootstrapのバージョン変更について書いていきたいと思います。
経緯はこうです。ポートフォリオ製作の中、週一の専用メンタリングがあり時間もわずかのところでメンターの方から
『あれ?bootstrapは3を使ってるんですね!』
な、なんだ!? 教材を参考にして制作を進めてるからそもそもバージョンにこだわりがなくてbootstrap3になっていたわけだが何かまずいのかな?と聞いてみると
『今はbootstrap4が主流ですね。特にこだわりがなければ新しいのを使った方がいいですよー。あとは今であれば困ったときにbootstrap4の方が似たようなケースも多いと思うので解決しやすいですよ!!』
なるほど。そしたらどうせ今後も使う機会もあると思うので新しいbootstrap4にバージョンを変更しよう!!
と意気込み、以下の記事を参考にしながらやってみました。
https://qiita.com/NaokiIshimura/items/c8db09daefff5c11dadf
なんだー簡単じゃんと思い いざアプリを立ち上げると
全然導入できねえ
こんなにバージョン更新が難しいとは。。。
やったこと
gemfile中に以下を記述しbundle install
gem 'bootstrap', '~> 4.1.1' gem 'jquery-rails'sprockets-railsがv2.3.2.以上である必要があるらしいので以下コードでバージョン確認
$ bundle show |fgrep sprockets-rails * sprockets-rails (3.2.1) 問題なしapp/assets/stylesheets/application.scssの中に@import "bootstrap";があることを確認。またファイル名がcssのままだとよくないのでscssに変えておく
ここも今までのbootstrap3導入まででやっていたことなので問題なし。
ブートストラップJavaScriptはjQueryに依存しています。Rails 5.1以降を使用している場合は、
jquery-rails
gemをGemfileに追加します。gem ' jquery-rails ' ここもbootstrap3導入まででやっていたことなので問題なし。application.jsに以下を記述する。
//= require jquery3 //= require popper //= require bootstrap-sprocketsrails s を再度して立ち上げる
エラー発生
内容をググりながらみていくと
Sass::SyntaxError in Pages#index
シンタックスエラーなのでコンパイルがうまくいってないのかな?
念のため他のページで読み込んでみるも特にエラー内容は変わらず
File to import not found or unreadable: bootstrap-sprockets.
この一行で検索をかけるとhttp://geekday.hatenablog.com/entry/2017/03/31/021052同じような境遇の方がいたので早速みてみるも解決せず
タイポもなさそうだしバンドルインストール後railsサーバー再起動するも変わらずエラーhttps://github.com/twbs/bootstrap-rubygem
bootstrap4の公式手順を見るも特にやってないことはないんだけどなあと途方に暮れました。まじで
ここから解決方法!!!
というわけでメンターの方に助けを求めると
まずGemファイル内のgem 'bootstrap-sass'を削除した方がいいと
これはbootstrap3を導入するときの記述なので本質的なエラーとは関係ないかもしれないが余計な影響があるかもしれない
このエラー画像の下の赤いラインなんですが
@import "bootstrap-sprockets";
app/assets/stylesheets/application.scssの中にbootstrap3の名残で書いていたのですが、これがそもそもbootstrap4では必要がないらしいです なのでこれを削除@import "bootstrap-sprockets"; File to import not found or unreadable: bootstrap-sprockets.とエラーメッセージが出ているのでこちらのファイルがないのに読み込みにいってます。 なので余談ですがapp/assets/stylesheets/application.scssの中に適当なファイル名を追記すると同じエラーが出ました。(@import "aaaaa";実際にこんなファイルはないので読み込めないですと表示されます)
再度railsサーバー再起動すると無事に表示!!
3から4に変えたことでデザインは崩れていましたが。そもそも
いやーここまで長かった。スタックオーバーフロウの英語の記事もGoogle先生に翻訳してもらいながら他の関係ありそうな記事を何件も読み半日以上格闘してました。
今回も残念ながら一人での解決はできませんでしたが惜しいところまで来ていたかと思います。
今後のエラー解決方法としては
バージョンを変える場合は以前のバージョンと更新したいバージョンの公式説明を読んでみる
これに関しては4の導入説明は読んでいたけど3の導入説明は探していなかったので3の記事を読んでいたら導入方法の違いがわかってもしかしたら解決できたかもしれません。更新手順を進める前にgitにpushしてからいろいろ変更しても大丈夫なようにすれば気軽に怪しい場所を削除して解決できるかなと思いました。
ニッチではありますが同じ境遇で同じエラーで困っている方は是非参考にしてください。
- 投稿日:2020-03-19T02:11:42+09:00
ec2をターミナルで操作するときに詰まった話(fatal: Could not read from remote repository.)
(デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
を参考に、AWSにrailsアプリをあげようとしていたときの凡ミスについて。エラー箇所について
上記の記事で
[~]$ ssh mumu_key_rsaでログインした後に、
[ユーザー名|~]$ vim .gitconfigで、諸々の設定を記述するところがある。
そこで、記事通り、下記のように設定すればよかった。
[user] name = your_name (#gitに登録した自分の名前) email = hoge@hoge.com (#git登録時の自分のメアド) [alias] (#これはお好きに) a = add b = branch ch = checkout st = status [color] (#色付け) ui = true # githubの場合 [url "github:"] (#pull、pushのための設定) InsteadOf = https://github.com/ InsteadOf = git@github.com:しかしながら、筆者は
[user] name = your_name (#gitに登録した自分の名前) email = hoge@hoge.com (#git登録時の自分のメアド) [alias] (#これはお好きに) a = add b = branch ch = checkout st = status [color] (#色付け) ui = true # githubの場合 [url "github:"] (#pull、pushのための設定) InsteadOf = https://github.com/(ここに実際にcloneしたいアプリのレポジトリURLを書いていた) InsteadOf = git@github.com:(ここに実際にcloneしたいアプリのレポジトリURLを書いていた)上記を見ていただければ分かる通り、無駄にレポジトリURLを記載してしまっていた。
その結果、git cloneでfatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.と、言われてしまったのだった。
まとめ
(デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
この記事では、丁寧にコメントでここには○○を記述などと書いてくれている。
それをちゃんと読んでいなかった筆者は簡単な設定ミスで結構苦労した(3時間も使ってしまった)。
みなさんが、そして未来の自分が再びこんな凡ミスを犯さないためにも、備忘録的に書かせていただきました。
- 投稿日:2020-03-19T01:32:33+09:00
マイグレーション操作
はじめに
「Ruby on Rails 5 速習実践ガイド」の本の内容(Chapter4-1)に沿ってまとめと、他に調べて知ったことも書いてみようと思います。
(内容薄いですが、、、、)Ruby on Rails 5 速習実践ガイド(Chapter4-1)
?マイグレーションの適用
2つのステップ
マイグレーションは基本的に2つのステップで行います。
1. Rubyのコードで、データベースのスキーマを変更するファイル、 「マイグレーション」ファイル を作成する
2.rails db:migrate
コマンドで、作成した「マイグレーション」ファイルをデータベースに適用する1つのマイグレーションは1つのバージョン
1つのマイグレーション(ファイル)が、 1つのバージョンとして、扱われます。
マイグレーションファイルを作成しただけでは、データベースは変更されず(バージョンは上がらず)、マイグレーションファイルを適用するとデータベースが変更されます。
マイグレーションを取り消す(バージョンを下げる)にも、マイグレーションファイルを削除するだけでは変更されないため、取り消すコマンドを実行して、操作を適用します。?バージョンの上げ下げ
下のマイグレーションファイルは、Userテーブル作成し、nameカラムとemailカラムを持つことを記述されています。
changeメソッド
の中に、「Userテーブルを作成する」というコードが書かれていれば、
マイグレーションの適用を取り消す際には、「Userテーブルを削除する」というコードが書かれているかのように処理をしてくれます。db/migrate/[timestamp]_create_users.rbclass CreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| t.string :name t.string :email t.timestamps end end endこちらのマイグレーションファイルは、nameカラムに入る文字列の長さを制限しています。
upメソッド
にバージョンを上げる処理、downメソッド
にバージョンを下げる処理を記述しています。db/migrate/[timestamp]_change_users_name_limit10.rbclass ChangeUsersNameLimit10 < ActiveRecord::Migration[6.0] def up change_column :Users, :name, :string, limit: 30 end def down change_column :Users, :name, :string end end?schema.rbについて
Railsは、データベースの構造(スキーマ)を
db/schema.rb
というファイルに自動で出力します。
テーブル、カラムの構造を確認できます。Railsガイドには、このように書かれています。
Railsのマイグレーションは強力ではありますが、データベースのスキーマを作成するための信頼できる情報源ではありません。
信頼できる情報源は、やはりデータベースです。Railsは、デフォルトでデータベーススキーマの最新の状態のキャプチャを試みるdb/schema.rbを生成します。?主なコマンド
migrationまわり
migrationに関する主なコマンドまとめです
コマンド 意味 bin/rails db:migrate 最新までマイグレーションを適用する bin/rails db:migrate VERSION=20200319 特定のバージョンまでマイグレーションが適用されていた状態にする bin/rails db:rollback バージョンを1つ戻す bin/rails db:rollback STEP=2 バージョンを指定したステップ数だけ戻す bin/rails db:migrate:redo バージョンを1つ戻してから1つ上げる bin/rails db:version 現在の適応されているバージョンを表示する dbコマンド
主なdbコマンドも少しまとめてみました
コマンド 意味 bin/rails db:create データベースが作成される bin/rails db:drop データベースの削除される bin/rails db:reset db:dropし、db/schema.rbにもとづいてデータベースを作り直す おしまい
↓こちら参考にしました?
Ruby on Rails 5 速習実践ガイド
Railsガイド
rake or rails コマンドでdbを扱うときのメモ
- 投稿日:2020-03-19T00:45:35+09:00
Rails6 Action Text アップロードされた画像のファイル名と画像サイズを非表示にする方法
こんにちは、「おすし」です。
最近ぶろぐを始めようと思い、 Action Txet を Rails6 で使おうと思い、導入までは順調だったのですが、いざ画像をアップロードすると、、、
なんとアップロードした画像の下にデフォルトでファイル名と画像サイズが表示されています!!!!
解決方法は....Action Textを導入した時に自動的に作成されたこのファイルから...↓
views/activestorage/blobs/_blob.html.erb <figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>"> <% if blob.representable? %> <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> <% end %> <figcaption class="attachment__caption"> <% if caption = blob.try(:caption) %> <%= caption %> <% else %> <span class="attachment__name"><%= blob.filename %></span> <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span> <% end %> </figcaption> </figure>figcaptionタグ含め、ネストされているコードを全て消します。
views/activestorage/blobs/_blob.html.erb <figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>"> <% if blob.representable? %> <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> <% end %> </figure>これだけ!
見てくださりありがとうございます。
それでは、お体ご自愛ください。
- 投稿日:2020-03-19T00:31:07+09:00
Ruby on Rails 削除関連まとめ
1. はじめに
アプリの作り始めに、「なんか気に入らないから1回削除して一から作り直したい」と思ったことはありませんか?
私はあります。そんな時に必要になる操作をまとめました。
すでにアプリを作りこんでいる場合は、削除して作り直すわけにもいきませんから変更の方法を探してみてください。自分の環境
- ruby 2.6.5
- Rails 6.0.2
- macOS Catalina 10.15.3
2. アプリの削除
アプリの削除をするにはアプリのフォルダを削除すればいいのですが、その前にデータベースを削除しておきましょう。
同じ名前でアプリを作り直したりしたときに以前のデータベースを利用してしまい、不具合が起きる可能性があります。
アプリケーションフォルダ内で、$ rails db:dropこれでデータベースが削除されます。
そのあとは、以下コマンドでアプリフォルダを削除してもいいですし、ゴミ箱へと放り込んでもいいでしょう。$ cd .. (1つ上のフォルダへ) $ rm -rf [アプリ名]ちなみに上記コマンドの意味は、
- rm = 削除するというコマンド
- -rf = ファイルでなくフォルダを削除するよという -r と「」というメッセージ表示はいらないよという -f の 組み合わせ
- . = 現在のフォルダ
3. コントローラの削除
アプリケーションフォルダ内で以下のコマンドを実行します。
作成の際のrails generate
はrails g
と省略できますが、destroy
は出来ません。
ルーティングは自分でconfig/routes.rb
をいじって消しましょう。$ rails destroy controller [削除したいコントローラ名]4. モデルの削除
マイグレーションを実行する前か後かで操作が変わるので注意。マイグレーション実行というのは、言い換えればデータベースにテーブルを作ること、もしくは
rails db:migrate
を実行することです。わからなかったら実行後の操作をしてみてください。マイグレーション実行前
アプリケーションフォルダ内で以下のコマンドを実行します。
作成の際のrails generate
はrails g
と省略できますが、destroyは出来ません。$ rails destroy model [削除したいモデル名]マイグレーション実行後
まずはマイグレーションまでしてみましょう。以下コマンドを実行。
説明の都合上、2つのモデルを作ってマイグレーションします。(なんの情報も持っていないモデルだけど気にしない。本当はカラム名:データ型
を後ろにつけます)$ rails g model user ← モデル作成 $ rails db:create ← データベース作成(まだデータベースを作っていない場合) $ rails db:migrate ← テーブル作成 $ rails g model post $ rails db:migrate (ここでやるから先の rails db:migrate はやらなくてもいい)モデルを削除する際には、データベースにテーブルが作成されてしまっているのでそちらを削除してからモデルを削除する必要があります。
まずは以下コマンドを実行してみましょう。
$ rails db:migrate:statusマイグレーションを実行した一覧が出てきます。これが
Status Migration ID Migration Name -------------------------------------------------- up 20200318134652 Create users up 20200318134702 Create postsStatusがupになっているということはこのマイグレーションが実行されている(テーブルが
作られている)ということ。以下コマンドのどれかを実行して、削除したいモデルのマイグレーションを取り消しましょう。
$ rails db:rollback (1つだけ前の状態に戻す) $ rails db:rollback STEP=2 (2つ前の状態に戻す) $ rails db rollback VERSION=20200318134652 (Migration ID:20200318134652のマイグレーションまで実行された状態に戻す)マイグレーションが2つくらいなら
rails db:rollback
を2回やればいいですが、たくさん戻したいならステップ数やバージョンを指定すると楽ですね。(不整合が起きるため、過去の特定のマイグレーションだけを取り消すことはできません。)これで実行したマイグレーションが取り消されたので、あとはマイグレーション実行前と同様に
rails destroy [モデル名]
で削除しましょう。マイグレーション取り消しの前にモデルを削除してしまった場合
せっかちで先に
rails destroy [モデル名]
を実行してしまった人のため。
例えば先の例でpostモデルを削除してしまったとします。するとpostのマイグレーションファイルも削除されてしまいrails db:rollbackでマイグレーションを取り消すことすらできなくなります。(絶望)その場合は、まず以下コマンドで新しくマイグレーションファイルを作成します。
$ rails g migration [マイグレーション名]マイグレーション名はなんでもいいですが、わかりやすくdrop_postとでもしておきましょう。
するとdb/migrate/内に以下ファイルが作成されます。
20200318143822_drop_post.rbclass DropPost < ActiveRecord::Migration[6.0] def change end endchangeメソッド内に以下の様に追記しましょう。
20200318143822_drop_post.rbclass DropPost < ActiveRecord::Migration[6.0] def change drop_table :post end endそしてマイグレーションを実行します。するとpostテーブルが削除されているため一件落着。
$ rails db:migrate無駄なマイグレーションファイルが残ってしまうのが自分的に嫌です。ファイルを削除しても問題ないけど
rails db:migrate:status
で表示される履歴の中にはしっかり残っています。(※マイグレーションファイルは削除しない様にしましょう)Status Migration ID Migration Name -------------------------------------------------- up 20200318145751 Create users up 20200318150431 ********** NO FILE ********** up 20200318150544 ********** NO FILE **********5. scaffoldで作成したモデルやコントローラ等の削除
rails g scaffold [モデル名] カラム名:データ型 (カラム名:データ型...)
でモデルやコントローラやルーティングなどを一括作成してくれます。詳しくは別記事を参照してください。rails g scaffoldで作成したんだからもちろん削除は以下コマンド。全部スッキリ削除してくれます。
rails destroy scaffold [モデル名]6. データベース内のデータを削除
モデルやコントローラ、ビューなどを作成し、色々試していているとデータベース内のデータがごちゃってきて初期状態に
戻したい時があると思います。そういうときは以下コマンドを実施。rails db:reset今あるデータベースを削除して新しくもう一度作ってくれます。
db/seeds.rb
を使って初期データ投入を行っている場合は初期データ投入も同時にやってくれるので、自分でrails db:seed
を行うと二重にデータが入ってしまいます。7. さいごに
他にも削除系の操作があれば教えてください。追記させていただきます。