- 投稿日:2020-07-07T23:14:12+09:00
unless をリライトするために
発端
現在見ている他人様のコードに、↓なコードがあるわけだ。
tgtunless hash.has_key?("1") || hash.has_key?("2") || hash.has_key?("3") || arr1.size == 0 || arr2.size == 0 .... end実際には否定とか混ってたりする。テスト実行するにも、膨大なコードのど真ん中。
他にも複数条件のunless
文がけっこう、、、
俺のスカスカな脳味噌では、挙動が想像出来ない。お手上げ。ググってみてもド・モルガンの説明なんて、精々 2つの条件で説明してる程度
仕方ないので、確認用の雛形スクリプトを作る。
コンセプト
まずは、2つの条件で。
条件式の代りに 0, 1 の値を呼ぶ。2.plmy @d = ( [0,0],[1,0],[0,1],[1,1] ) ; for my $r ( @d ){ print join "", @{$r} unless $r->[0] || $r->[1] ; }$ perl -l 2.pl 00
unless A || B
の成立する条件は、一つ目の条件式が偽(0)、二つ目の条件式も偽(0)だと分る。つまりif ! A and ! B
本題
じゃ、tgt の場合は?
高々5ヶなのでごり押しのコード
$ ruby -e 'p [0,1].product([0,1],[0,1],[0,1],[0,1])' [[0, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 1], [0, 1, 0, 0, 0], [0, 1, 0, 0, 1], [0, 1, 1, 0, 0], [0, 1, 1, 0, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 1], [1, 0, 1, 0, 0], [1, 0, 1, 0, 1], [1, 1, 0, 0, 0], [1, 1, 0, 0, 1], [1, 1, 1, 0, 0], [1, 1, 1, 0, 1]]これをソースコードに埋め込んで
5.pl#!/usr/bin/env perl my @d = ( [0, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 0, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 1], [0, 0, 1, 1, 0], [0, 0, 1, 1, 1], [0, 1, 0, 0, 0], [0, 1, 0, 0, 1], [0, 1, 0, 1, 0], [0, 1, 0, 1, 1], [0, 1, 1, 0, 0], [0, 1, 1, 0, 1], [0, 1, 1, 1, 0], [0, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 1], [1, 0, 0, 1, 0], [1, 0, 0, 1, 1], [1, 0, 1, 0, 0], [1, 0, 1, 0, 1], [1, 0, 1, 1, 0], [1, 0, 1, 1, 1], [1, 1, 0, 0, 0], [1, 1, 0, 0, 1], [1, 1, 0, 1, 0], [1, 1, 0, 1, 1], [1, 1, 1, 0, 0], [1, 1, 1, 0, 1], [1, 1, 1, 1, 0], [1, 1, 1, 1, 1] ) ; for my $r ( @d ){ print join "", @{$r} unless $r->[0] || $r->[1] || $r->[2] || $r->[3] || $r->[4] ; }実行する。
$ perl -l 5.pl 00000改良
ついでに数も変えられる様に、
@d
生成をperl
で記載1。5.2.pl#!/usr/bin/env perl sub comb{ my $in = shift ; # 0 から、2進数の組合せ -1 までの十進数を、0x回数埋めの 2進数に変換した後、 # 1文字ずつ分割。配列リファレンスにする。で、戻り値は、Array of Arrays map{ [ unpack '(A)*', sprintf "%0${in}b", $_ ] } 0 .. 2 ** $in - 1 ; } my @d = comb $ARGV[0] ; for my $r ( @d ){ # $ARGV[0] - 1 回も || を書くのは面倒臭いので、 # || で連結した文字列を、eval してそれを unless の引数にしてる。 # 実際には、検証対象に合せたコードに変更 print join "", @{$r} unless eval join '||', map{ $r->[$_] } 0 .. $ARGV[0] - 1 ; }$ perl -l 5.2.pl 12 000000000000あとは、
||
を&&
にするとか、!
を付けるとか、テストしたい条件文に合せて、その場その場で対応する。ああ、これで、ストレス少なく、
unless
をif
に変えられる。蛇足
2進数を利用しない時。
sub comb { my $in = shift ; # ([0,0,0..])な配列を作る my @d = ( [(0)x$in] ) ; # キャッシュ用ハッシュ my %seen ; # @d を舐めるのだが、@d はループ内で push されて数が増えるので # 抜ける条件は別に付ける for my $r ( @d ){ # $r = [ x,x,x,x,x ... ]の要素を順番に 1 に変えて、 # 未知の組合せだったら、@d に追加 push @d, grep{ ! $seen{ join "", @{$_} } ++ } map { my @k = @{$r} ; $k[$_] = 1 ; [@k] } 0 .. $in - 1 ; # [全部 1 ] が最後の組合せ last if +(join '', @{$d[-1]}) eq '1' x $in ; } return @d ; }お作法本的にはタブーなコード2。
こちらだと、二桁にすると厳しい。
- 投稿日:2020-07-07T22:34:50+09:00
Rubyでgmailからメールを送信する
はじめに
参加している勉強会でプログラムを書く練習課題として、rubyでメールを送るというお題があり、実施した内容を以下に記載します。
ちなみに自分が普段使っているgmailから送るプログラムになります。
制限時間がある中での課題だったので、焦りながら実施しましたが、思った以上に参考文献、ライブラリが揃っており、助けられました。
実施環境、必要なもの
- OS :mac
- ruby 2.6.6
- Googleアカウント
実施手順
Googleアプリパスワードの取得
アプリからメール送信する際の認証には、googleアカウントのパスワードをそのまま使うのではなく、googleのアカウント設定で発行するアプリパスワードを使って認証を行います。
(パスワードをそのまま使うより、セキュリティ的におすすめな方法)上記画面から、「セキュリティ」→「アプリパスワード」を選択後、アプリ:メール、デバイス(自分の場合はmac)を選択後に、生成ボタンを押すと、アプリパスワードが表示されます。
※なお、前提としてgoogleアカウントの二段階認証が有効になっている必要があります。
ruby-gmail gemのインストール
大変ありがたいことに、rubyにはgmailを送信するためのgemがあるので、こちらを利用します。
gem install ruby-gmailruby-gmail gemには単にメール送信の他に、受信メールを読んだり、編集したりといろいろ機能があって面白そう。
環境変数の設定(gmailアドレス、アプリパスワード)
セキュリティ観点からgmailアドレスと先に取得したアプリパスワードは、プログラムにベタ書きではなく、環境変数に設定し、プログラムで取得することにします。
export GMAIL_ID="送信したいgmailアドレス" export GMAIL_PASS="gmailのアプリパスワード"設定した環境変数を反映させます。
source ~/.bash_profileメール送信プログラムの作成
今回は、コマンド上で、任意の送信先アドレス、件名、本文を入力できるようにしています。
require "gmail" USERNAME = ENV[ "GMAIL_ID" ] PASSWORD = ENV[ "GMAIL_PASS"] gmail = Gmail.new(USERNAME, PASSWORD) puts "送信先のアドレスを入力してください" address_to = gets.chomp puts "件名を入力してください" title = gets.chomp puts "本文を入力してください" text = gets message = gmail.generate_message do to address_to subject title html_part do content_type "text/html; charset=UTF-8" body "<p>" + text + "</p>" end end gmail.deliver(message) gmail.logout参考記事
プログラムの大部分はこちらを参考にさせていただきました。大変感謝です。
- 投稿日:2020-07-07T22:23:06+09:00
【Ruby】繰り返しの制御
今回は繰り返しの制御について書いていきます。
繰り返しの途中で処理を中断したり、次にスキップしたい場合がありますが、
繰り返しの制御の命令を使うことで実現できます。break
breakは繰り返しを中断し、繰り返し処理の中から抜けます。
# サンプルプログラム num = 0 loop do num += 1 if num > 10 break end end puts num前回の記事で書いたものとほぼ同じですが、if式をシンプルな形にしています。
numが10より大きい、つまり11となった時点でloopメソッドから抜け出し、11が出力されます。next
nextは次の繰り返し処理に移ります。
# サンプルプログラム for num in 1..10 if num.odd? next end puts num endodd?メソッドは値が奇数の場合にtrueを返します。
よって、変数numの値が奇数の場合はnextを通るので、変数numの値の出力はせずに次の繰り返し処理に移ります。
結果として2,4,6,8,10が出力されます。redo
redoはもう一度同じ繰り返し処理をします。
# サンプルプログラム for num in 1..10 if num.odd? redo end puts num endnextで記述したサンプルプログラムのnextをredoに置き換えたものですが、
この場合、numの値が1のまま無限ループとなります。redoがどういう場合に使われるか現時点では想像がつかないのですが、あまり使われないようです。
今回の繰り返しの制御については以上となります。
- 投稿日:2020-07-07T21:51:14+09:00
ParsingとStoringって何
- 投稿日:2020-07-07T21:13:22+09:00
【Rails】複数のDB処理をまとめる transaction を実装してみた
はじめに
Rails でアプリを開発していて、複数テーブルのデータを同時に作成する、という処理を実装していた。
その処理において、どちらかの処理が失敗した場合に双方の処理をなかったことにする transaction という概念があることを知ったので備忘録兼アウトプットとして、 transaction についておよび、実装した内容について書く。transaction とは
「transaction」という言葉の定義を調べると
【処理、取り扱い、処置、業務、取引、売買、会報、紀要、議事録】 このように出てくる。ITやプログラミングにおいては
「複数の処理を一つにまとめた分割不可能なもの」と定義づけることが出来そうです。
こちらの記事がトランザクションの概念について非常にわかりやすいくまとめられており、参考にさせていただきました。
transaction メソッド使い方
- 複数の処理を一つのまとまった処理として扱う
- 一つでも処理に失敗した場合は、トランザクション全体として失敗となる
- 失敗した場合は、全ての処理がなかったこととなる
基本的な構文としてはこうなる
モデル.transaction do # テーブルへのアクセス処理 # テーブルへのアクセス処理 end # トランザクション処理が成功した場合の処理 rescue => e # トランザクション処理が失敗した場合の処理注意点としては「処理失敗時には例外を発生させるメソッドを使用する」こと。
トランザクションは、含まれる処理のいずれか1つでも失敗すると、トランザクション内のすべての処理をなかったことにするが、そのなかったことにする条件が「例外の発生」となる。
では実際に実装してみる。
実装
今回開発していたアプリにはユーザーのグループ化機能があった。
そこで、グループを新規作成するときにグループ作成をしたユーザーは自動的にグループに所属するユーザーとなる、という仕様を想定。
そこでグループ作成をした際に、思わぬ動作が起きてしまうことを避けるためにトランザクションの利用を検討。groupsテーブルインスタンスを作成すると同時に、ログインユーザーのidをuser_idカラムとする group_usersテーブル(usersテーブルとgroupsテーブルの中間テーブル)が作成されるようにしたかった。
- groupsテーブルインスタンスの作成
- group_usersテーブルインスタンスの作成
この 1, 2 のうちどちらかの処理が何らかの理由により失敗した場合、双方の処理がなかったこととなるように groups コントローラの create アクションで transaction を活用する。
groups_controller.rb# createアクション部分を抜粋 # 変数current_userにはログインユーザーのインスタンスが格納 def create @group = Group.new(group_params) # トランザクションを適用(グループの作成と中間テーブルを同時作成) # save! と create! と「!」がついている点に注意! @group.transaction do @group.save! current_user.group_users.create!(group_id: @group.id, permission: true) end # トランザクション成功時の処理 flash[:success] = '新しいグループを作成しました' redirect_to @group rescue => e # トランザクション失敗時の処理 flash.now[:danger] = 'グループ作成に失敗しました' render :new endこの transaction 内での処理には両方とも「!」がついており、テーブルデータ作成失敗時には例外が発生するメソッドを使っていることに注意!
仮に transaction を利用せずに以下ように実装した場合は、何らかの理由で group_usersテーブルの作成が失敗した場合に無人のグループが作成されてしまう懸念がある。
groups_controller.rb# transactionを利用しない場合 def create @group = Group.new(group_params) if @group.save current_user.group_users.create(group_id: @group.id, permission: true) flash[:success] = '新しいグループを作成しました' redirect_to @group else flash.now[:danger] = 'グループ作成に失敗しました' render :new: end end最後に
記事を読んでいただきありがとうございます!
今回調べながら何とか実装してみたのですが、正直トランザクションについての理解はそこまで深くないです。誤りやより良い記述方法などがあれば、気軽にコメント等いただければ幸いです。
下記の記事、参考にさせていただきました。ありがとうございました。
- 投稿日:2020-07-07T16:45:48+09:00
railsでrspecを使用中にハマったこと
初心者がrailsでrspecを用いてテストを記述する際にハマったことを残しておきます。
rspecでcontrollerのテストを試みたところエラーが頻発しました。どこを直してもうまくいかなかったので、一度参考サイト通りに記述し、何が問題かを調査することにしました。しかし、それでもうまくいかない。。。
そこで設定を見直したところ、controllerのテストはrails5から非推奨になっており、以下のように変更する必要がありました。model → model(そのまま)
controller → request
画面遷移のテスト → systemのようにフォルダを作成する必要があり、rails_helperの設定も上記にならい記述する必要があった。
参考記事はcontrollerとrequestが混在しているため注意する必要がある。また、最近のrailsではコントローラーのテストは非推奨になり、
create,destroy,edit,updateのテストが記述してあれば十分になったらしい。
- 投稿日:2020-07-07T16:34:41+09:00
railsで開発中にAWSから高額請求されたが、、
はじめに以下の記事にあるように、railsでアプリを開発中に初期設定のミスが原因で高額請求に至った。
https://qiita.com/381704/items/d5216295eadd67eb9e8c完全に注意不足であり、しっかり利用してしまったあとなので支払うしかないと思っていたが、駄目元でAWSのサポートセンターに以下のようなメールを送ってみた。(本文を載せるのは抵抗があったが、証拠&同じ状況の人の希望になればと思い残しておく)
2日後にAWSサポートより返信が来た。返信内容には、現在料金が発生しているRDSのインスタンスとスナップショットの削除をすることとあり、その後に返金が可能かの相談にはいるということだ。
内容通り、RDSの削除をして再度AWSに削除完了のメールを送信した。
その2日後AWSサポートより返答があり、今回に限り返金措置を設けてくださるとのこと!!!請求料金は合計600$以上になったが、AWS様より返金をしてくださり、最終的な請求料金は100$ほどになった。落ち度は完全に私のほうにあるにも関わらず、今回の対応をしてくださったことは本当に感謝してもしきれないほどだ。
離職中だったので金銭的に苦しい状況だったため本当に助かりました。ありがとうございました。
反省として請求アラームを2個付け、UdemyでAWSに関する教材を購入し基礎からAWSの利用法を学び直しました。
これからもサービスを利用させていただきます。
- 投稿日:2020-07-07T16:28:10+09:00
Rails5でECサイトを作る④ ~ヘッダーとフッター~
はじめに
架空のベーカリーで買い物できるECサイトを作るシリーズ、Rails5でECサイトを作る③の続きです。
今回は、ヘッダーとフッターを作ります。せっかくなのでレスポンシブ対応にしてみました。ソースコード
https://github.com/Sn16799/bakeryFUMIZUKI
配色
いきなり余談ですが、サイト全体のテーマカラーを決めました。店名(架空)が文月なので、夏らしい青系統の色でまとめます。
カラーコードも一応載せておきます。ご参考までに。濃青……#120136、rgb(18,1,54)
中青……#035aa6、rgb(3,90,166)
淡青……#40bad5、grb(64,186,213)
ワンポイント黄……#fcbf1e、rgb(252,191,30)ヘッダー
app/views/layouts内に、ヘッダー用の部分テンプレートを作ります。ファイル名は、_header.html.erbとしました。
管理者でログインした時と顧客がログインした時、ログインしていない時の3パターンで表示が変わるように条件分岐します。
顧客ログイン時に「ようこそ、〇〇さん!」とメッセージを表示したいのですが、データベース上は苗字と名前を別々で保存しているため、viewのコードが煩雑になってしまいます。そのため、Modelのファイルにちょい足しして、苗字と名前を連結した文字列を出力できるようにします。app/model/customer.rbdef full_name self.family_name + " " + self.first_name endこれでviewやcontrollerでfull_nameと入力すれば、フルネームで表示できるようになりました!
app/views/layouts/_header.html.erb<header class="container-fluid middle-blue-back"> <nav class="navbar navbar-expand-lg"> <!-- ロゴ画像。あとで差し替え。 --> <div> <%= link_to customer_top_path, style: 'color: #fcbf1e' do %> <h1>LOGO</h1> <% end %> </div> <!-- 画面幅が狭くなった時のみ出現するトグルボタン --> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarFumizuki" aria-controls="navbarFumizuki" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <!-- 各種リンク。管理者ログイン時と顧客ログイン時、非ログイン時で表示切替。 --> <div class="collapse navbar-collapse" id="navbarFumizuki"> <!-- 管理者 --> <ul class="navbar-nav mr-auto w-75 nav-justified"> <% if admin_signed_in? %> <div class="admin-message">管理者としてログインしています</div> <li class="nav-item"><%= link_to '商品一覧', admins_products_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to '会員一覧', admins_customers_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to '注文履歴一覧', admins_orders_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to 'ジャンル管理', admins_genres_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to 'ログアウト', destroy_admin_session_path, method: :delete, class: 'nav-link' %></li> <!-- 顧客 --> <% elsif customer_signed_in? %> <li class="nav-item"><%= link_to 'About', customer_about_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to 'マイページ', customer_path(current_customer.id), class: 'nav-link' %></li> <li class="nav-item"><%= link_to '商品一覧', products_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to 'カート', cart_items_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to 'ログアウト', destroy_customer_session_path, method: :delete, class: 'nav-link' %></li> <!-- 非ログイン --> <% else %> <li class="nav-item"><%= link_to 'About', customer_about_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to '商品一覧', products_path, class: 'nav-link' %></li> <li class="nav-item" ><%= link_to '新規登録', new_customer_registration_path, class: 'nav-link' %></li> <li class="nav-item"><%= link_to 'ログイン', new_customer_session_path, class: 'nav-link' %></li> <% end %> </ul> <!-- メッセージ(customer) or 検索窓(admin) --> <% if customer_signed_in? %> <p>ようこそ<%= current_customer.full_name %>さん!</p> <% else admin_signed_in? %> <!-- 検索フォームは仮。あとで機能するものを作って差し替え。 --> <form class="form-inline my-2 my-lg-0"> <input type="search" class="form-control mr-sm-2" placeholder="検索..." aria-label="検索..."> <button type="submit" class="btn btn-outline-success my-2 my-sm-0">検索 </button> </form> <% end %> </div> </nav> </header>フッター
特に機能をつけなかったのであってもなくても良いのですが、ないと寂しいので作ります。
app/views/layouts/_footer.html.erb<div class="container-fluid middle-blue-back"> <h3 class="footer-message">Bakery FUMIZUKI</h3> </div>青色の背景と、中心に黄色で「Bakery FUMIZUKI」の文字というシンプルな構成です。
おおまかな枠組みを作る
application.html.erbを編集して、サイト全体のレイアウトを調整します。
先ほど作ったヘッダーとフッターもここで読み込みます。app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title>Fumizuki</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <!-- レスポンシブ --> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- swiper --> <link rel="stylesheet" href="https://unpkg.com/swiper/css/swiper.min.css"> <script src="https://unpkg.com/swiper/js/swiper.min.js"></script> <!-- font awsome --> <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet"> </head> <body> <%= render 'layouts/header' %> <div class="container-fluid"> <div class="row"> <%= yield %> </div> </div> <%= render 'layouts/footer' %> </body> </html>真ん中あたりにあるswiperというのは、写真をスライド表示するためのライブラリです。今回の記事では使いませんが、便利なのでいずれお世話になるだろうと思って入れました。
その下のfont-awsomeは、リンクをコピーするだけで数多くのアイコンを無料で使える便利なサイトです。こちらもそのうち使うと思います。scssで装飾
HTML側で記述したクラス名に、各種の色を設定していきます。
app/assets/stylesheets/application.scss@import 'bootstrap'; .middle-blue-back { background-color: #035aa6 } .light_blue_letter { color: #40bad5 } .footer-message { line-height: 100px; text-align: center; color: #fcbf1e } // header .navbar-toggler { border-color: #40bad5; } .navbar-toggler .navbar-toggler-icon { background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgb(64,186,213)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E"); } .nav-link { color: #40bad5; }トップページも細工する
テーマカラーに決めた色見本がブラウザでどのように見えるのか確認したかったので、トップページで試してみました。後で正式なトップページを書くときに消します。
app/views/homes/top.html.erb<div class="col"> <h1>Homes#top</h1> <div class="row"> <div class="col-3" style="height: 100px; background-color: #120136"></div> <div class="col-3" style="height: 100px; background-color: #035aa6"></div> <div class="col-3" style="height: 100px; background-color: #40bad5"></div> <div class="col-3" style="height: 100px; background-color: #fcbf1e"></div> </div> </div>localhost:3000にアクセスしてみます。
ヘッダー、フッターとも問題なく表示されています。
開発者ツールで画面幅を狭くすると、きちんとハンバーガーアイコンになりました!
後記
Bootstrapを使うとレスポンシブ対応も楽々できて、本当に便利な機能だなと思います。CSSも多少書いていますが、ほぼ色の指定をしているだけです。そのカラーコードも4色だけなので、アプリ全部を完成させても、CSSのコード量はほとんど増えないのではないでしょうか。
あと、ここまでお読みくださった方は薄々あることを思っておられるかも知れません。私もちょっと気になっています。
サイトのテーマカラー、どこかで見たことあるような。はい。完全にI●EAですね。
不覚にもサイトで表示するまで気付かなかったため、コードを書いてからビックリする事態となってしまいました。私はIK●A好きだから良いですけど、向こうは別に私のこと好きでも何でもないと思うので、このまま実装を続けたものか迷います。
一旦IKE●に見えてしまったら、サイトを見る度に「絶対この店、パン売ってないよな」と思ってしまうのも難点です。果たして私は●KEAから怒られずにサイトを完成させられるのか? 次回へ続く!
参考
Bootstrap4移行ガイド
Bootstrap4日本語リファレンス
とほほのBootstrap 4入門
Bootstrap4のハンバーガーメニューの色を変える方法
- 投稿日:2020-07-07T15:51:35+09:00
URLエンコードについて調べてみた
WEB上のPDFファイルが見れない
なぜかアップロードしたPDFファイルがリンク切れになっていたので
その調査内容を記録します。ユーザ環境
- MacBook
- Chrome
アプリケーション環境
- AWS EC2
- AWS S3
- ruby 2.6.5
- Rails 5.0.7.2
- refile (0.6.2)
- refile-s3 (0.2.0)
見れないファイルのパターン
チルダ「~」がファイル名に含まれているファイルはリンク切れになってしまう。
ファイルリンクを作成するコード
li = link_to attachment_url(file, :file), target: '_balnk' b-icon(icon="attachment") span.file__name = file.file_filename実際に生成されるhtml
<a target="_balnk" href="/attachments/xxxxxxx/store/xxxxxx/2020.3%7E2020.4%E3%83%86%E3%82%B9%E3%83%88.pdf"> <span class="file__name">2020.3~2020.4テスト.pdf</span> </a>日本語もちゃんとURLエンコードされているし、問題なさそう。
URL規約を調べてみた
URLで使用できる文字は規約で定められていて
いくつかの規約がありましたが、以下2つについてしらべてみました。
- RFC3986
- RFC1738
RFC1738
https://tools.ietf.org/html/rfc1738
Unsafe:
Characters can be unsafe for a number of reasons. The space
character is unsafe because significant spaces may disappear and
insignificant spaces may be introduced when URLs are transcribed or
typeset or subjected to the treatment of word-processing programs.
The characters "<" and ">" are unsafe because they are used as the
delimiters around URLs in free text; the quote mark (""") is used to
delimit URLs in some systems. The character "#" is unsafe and should
always be encoded because it is used in World Wide Web and in other
systems to delimit a URL from a fragment/anchor identifier that might
follow it. The character "%" is unsafe because it is used for
encodings of other characters. Other characters are unsafe because
gateways and other transport agents are known to sometimes modify
such characters. These characters are "{", "}", "|", "\", "^", "~",
"[", "]", and "`".
All unsafe characters must always be encoded within a URLチルダは使用するなら必ずエンコードして使わないといけないと明記されていました。
RFC3986
https://tools.ietf.org/html/rfc3986
2.3. Unreserved Characters
Characters that are allowed in a URI but do not have a reserved
purpose are called unreserved. These include uppercase and lowercase
letters, decimal digits, hyphen, period, underscore, and tilde.
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"チルダの扱いが「非予約文字」になっていてエンコードなしで使えそうです。
Amazon CloudFrontはどの規約に準拠しているのか?
URL規約を調べたところで
WEBアプリケーションの動作しているAWS環境を調べてみました。ユーザからRequestをうけるAmazonCloudFrontのドキュメントを見てたら
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Invalidation.htmlパスに ASCII 以外の文字が含まれるか、RFC 1783 に規定された安全でない文字が含まれる場合、その文字を URL エンコードします
という記述がありました。
なんで見れなかったのか?
上記、調査内容からするとチルダのエンコードで何かしら問題あったということになりますが、、
Railslink_to
で作成されたhtmlリンクは正しくエンコードされている。。<a target="_balnk" href="/attachments/xxxxxxx/store/xxxxxx/2020.3%7E2020.4%E3%83%86%E3%82%B9%E3%83%88.pdf"> <span class="file__name">2020.3~2020.4テスト.pdf</span> </a>ブラウザの問題?
Chrome と Safariで試したところ、SafariからはPDFファイルが見れた!!
Chrome アドレスバーの表示
https://xxxxxx/2020.3~2020.4テスト.pdfSafari アドレスバーの表示
https://xxxxxx/2020.3%7E2020.4テスト.pdfエンコードされたリンクを開く際、ブラウザで日本語にデコードしてくれるようだが、
そのデコードによる問題かな。。と推測。
- 投稿日:2020-07-07T14:59:27+09:00
[Rails]新しいページを増やす方法
Ruby on Railsのページを増やす手順
忘れないよう、自分用のメモ書きです。
手順
1.configのrouteファイルにURLと対応するアクションを記述
2.controllerに該当するアクションを追記
3.viewフォルダにhtml.erbファイルを新規作成※まったく0からのサイト作成ではなく
既存のプログラムに追加する想定。routeファイルにURLとアクションを記述
〜書き方〜
HTTPプロトコル ”ページを表示させたいURL” => ”コントローラ名#アクション名”
のように記述します。※「HTTPプロトコル」としましたが、ほとんどの場合「get」か「post」のどちらかです。
以下に具体例を示します。
route.rbget "images/index" => "images#index"〜/images/indexというURLへリクエストを受けた時に、
このプログラムでは、imagescontrollerの中の、indexアクションを実行しますという書き方になっています。controllerに該当するアクションを追記
images_controller.rbdef index end先ほど、routeファイルに書いたとおり、URLのリクエストを受けた後、
プログラムはimagescontrollerを見に来ます。そして、indexアクションを探して実行しようとします。
今回は、その流れそのものをひとつ増やす作業を行っているので該当するアクションを追記します。viewフォルダにhtml.rbを新規作成
最終的にブラウザ等で表示されるのはhtml.rbファイルです。
route→controller→html
※.rb省略
の順番で記述やファイルを追加していきましょう。index.html.rb<h1>sample</h1>
- 投稿日:2020-07-07T10:34:26+09:00
「bundle install」するとgem系のファイルについて大量にgit差分が発生してしまう
発生した背景
新しいgemを入れるときに、以下のコマンドを実行するとgitに大量に差分が発生することがあります。
コマンドbundle install --path vender/bundle(スクショの「Unstaged Files(1)」というところが、10000とかになったりする。ごめんなさい、再現ができなかったです)
この件について対応方法を検討したいと思います。
環境
項目 内容 OS.Catalina v10.15.4 Ruby v2.5.1 Ruby On Rails v5.2.4.3 Git 2.20.1 対応手順
【1】Gitignoreを編集する。
Gitignoreのフォーマットなるものがあります。
詳しくは参考文献「編集済みの.gitignoreを簡単に得る方法」を。
以下内容を掲載しておきます。.gitignore*.rbc capybara-*.html .rspec /log /tmp /db/*.sqlite3 /db/*.sqlite3-journal /public/system /coverage/ /spec/tmp **.orig rerun.txt pickle-email-*.html # TODO Comment out this rule if you are OK with secrets being uploaded to the repo config/initializers/secret_token.rb # Only include if you have production secrets in this file, which is no longer a Rails default # config/secrets.yml # dotenv # TODO Comment out this rule if environment variables can be committed .env ## Environment normalization: /.bundle /vendor/bundle # these should all be checked in to normalize the environment: # Gemfile.lock, .ruby-version, .ruby-gemset # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc # if using bower-rails ignore default bower_components path bower.json files /vendor/assets/bower_components *.bowerrc bower.json # Ignore pow environment settings .powenv # Ignore Byebug command history file. .byebug_history特に「/vendor/bundle」が重要ですね。
gitにあげるとパフォーマンスも落ちますし、よくないことだらけなので私は、上記を書き換えるだけでなく、既存のファイルに追記という形をとりました。参考文献
- 投稿日:2020-07-07T10:31:10+09:00
rails メソッド
railsメソッド
human_attribute_nameで多言語対応できる
const_get
https://docs.ruby-lang.org/ja/latest/method/Module/i/const_get.html
- 投稿日:2020-07-07T07:57:28+09:00
Ruby on Rails マイグレーションを取り消す
- 投稿日:2020-07-07T06:55:46+09:00
Ruby on Rails でアプリケーションを制作する。
Ruby on Rails でアプリケーションを新規作成する。
$ rails new アプリケーション名 -オプション名
- データベースに MySQL を使用する場合は、オプション名に
-d mysql
と記述する。
※ デフォルトは SQLite を使用している。データベースを作成する。
$ rails db:createルーティングを生成する。
config/routes.rbRails.application.routes.draw do [HTTPメソッド] '[URIパターン]', to: '[コントローラー名]#[アクション名]' root to: 'コントローラー名#アクション名' # ルートパス (get '/', to: '[コントローラー名]#[アクション名]') にリクエストする。 resources :コントローラー名, only: [:アクション名] # "resources"メソッドを使用すると、指定したコントローラーの 7つのアクション (index,new,create,show,edit,update,destroy) のルーティングが設定される。 # "only"オプションを使用すると、7つのアクション全てではなく、指定しただけのアクションのルーティングが設定される。 end
HTTPメソッドの種類
- GET:ページを表示する時に使用する。
- POST:フォームからデータを送信して、登録する時に使用する。
- PUT:データを変更する時に使用する。
- DELETE:データを削除する時に使用する。
アプリケーションのルーティングを確認する時はターミナルで
$ rails routes
を実行する。Prefix
Prefix名_path
と記述することで、リンク先等のパスとして扱える。コントローラーを作成する。
$ rails g controller コントローラー名
- ルーティングから送られたリクエストに対応する7つのアクション
index
:new
:create
:show
:edit
:update
:destroy
:モデルを作成する。
$rails g model モデル名
- マイグレーションファイルにテーブルに必要なカラムを記述する。
マイグレーションファイル.rbclass CreatePosts < ActiveRecord::Migration[5.2] def change create_table :posts do |t| t.型 :カラム名, null: false # "null: false" は空のデータが登録できないようにする必須項目に付けるバリデーション (モデルファイルにも要記述) t.timestamps end end end
- 型の種類
integer
:数値string
:文字列text
:文字列(長文)boolean
:選択肢datetime
:日付・時刻
- マイグレーションファイルに必要なカラムを記述したらマイグレーションをする。
$ rails db:migrate
- もし、マイグレーションした後にマイグレーションファイルの修正をする場合には、
$ rails db:rollback
を実行して、データベースから差し戻す必要がある。- 現状 マイグレーションファイルがデータベースに適用されているか確認するには
$ rails db:migrate:status
を実行する。データベースに一度 上げたテーブルの情報を追加・削除・変更するには…
$ rails g migration Addカラム名Toテーブル名 カラム名:型
という形で実行する。
Addカラム名Toテーブル名
の部分は、単語の頭文字を大文字にして、スペースを開けずに記述する。ヘルパーメソッド
<%= link_to 'リンクに表示する文字', 'リンク先のURL' %>ビューファイルにデータベースのテーブルに保存されている値を表示する。
- コントローラーでモデルからテーブルの値を取得する。
_controller.rbclass PostsController < ApplicationController def アクション名 @変数名 = " ● ● ● " # コントローラーでインスタンス変数を定義しておくと、ビューファイルで "<%= @変数名 %>" 呼び出すことができる。 @変数名 = モデル名.ActiveRecordクラスメソッド # 取得したい値があるモデル名の ActiveRecord クラスメソッドを指定して、インスタンス変数に代入する。すると、ビューファイルで変数名を指定することで値を表示できる。 end end
- ActiveRecord クラスメソッドの種類
all
:テーブルの全てのデータを取得する。find(●)
:テーブルの中の特定のレコードを取得する。new
:新しくレコードを生成する。save
:特定のレコードに保存する。
- 取得した値をビューファイルに記述する。
<%= @変数名.カラム名 %> <!-- "find(●)" メソッドを指定して、特定のレコードを取得した場合は、代入した変数名に表示したいカラム名を記述する。 --> <% @コントローラで代入したインスタンス変数名.each do |変数名| %> <%= 変数名.カラム名 %> <% end %> <!-- "all" メソッドを指定して、複数のレコードを取得した場合は、Each文を利用してレコード 1つずつ取り出してから表示する。 -->フォームを作成する。
ビューファイルにフォームを作成する。
<%= form_with model: @コントローラでモデルに新しくレコードを生成する値を代入するインスタンス変数名, url: フォームを送信するコントローラの Createアクションの Prefix_path, local: true do |form| %> <%= form.フォームのヘルパーメソッドの種類 :カラムの名前 %> <% end %>
- " type="" " 属性の値の種類
type="text"
:テキストフォームtype="password"
:パスワードフォームtype="checkbox"
:チェックボックスtype="radio"
:ラジオボタンtype="submit"
:送信ボタンルーティングに送信ボタンを押した後のリクエスト先を記述する。
config/routes.rbpost '[URIパターン]', to: '[コントローラー名]#create' # フォームからデータを送信して 登録する操作をするので、HTTPメソッドに "POST" # データの投稿をするリクエストには、"Create" アクションコントローラでテーブルにレコードを追加する。
_controller.rbdef create モデル名.create(ストロングパラメータのメソッド名) # モデルにレコードを追加する為の .create メソッド # フォームから値を受け取る為にストロングパラメータを使用する。 end private def ストロングパラメータのメソッド名 params.require(:インスタンス変数名).permit(:フォームの "name" 属性の値) # フォームから送信されてきた値の中で、指定されたフォームを許可する。 end
- 投稿日:2020-07-07T06:55:13+09:00
ユーザー管理機能を実装する。 | Ruby on Rails
- Gemfile に
$ gem 'devise'
を追記して、$ bundle install
する。Devise の設定ファイルを作成し、 User モデルを作成する。
$ rails g devise:install
を実行して、Devise の設定ファイルを作成する。$ rails g devise user
を実行して、Devise の機能を持つ User モデルを作成する。
- この時に、ルーティングに
devise_for :users
という Devise の機能へリクエストするためのルーティングが生成される。$ rails db:migrate
を実行して、Devise の機能を持つ User モデルをマイグレートする。- ログイン画面等の Devise が持つビューファイルを変更したい場合は、
$ rails g devise:views
を実行してビューファイルを作成する。メールアドレスとパスワード以外の値を受け取れるようにする。
- Devise では、メールアドレスとパスワードしか値を受け取らないようにストロングパラメータが記述されているので、任意でフォームを追加した場合には、その値を受け取れるように記述する必要がある。
_controller.rbclass ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:追加したフォームの名前]) end endログインしている時としていない時で表示が変わるようにする。
- Devise をインストールすると、ユーザーがサインインしているかどうかを判断する
user_signed_in?
メソッドが使用できる。<% if user_signed_in? %> <!-- ユーザーがサインインしている場合に実行する処理を記述する。 --> <% else %> <!-- ユーザーがサインアウトしている場合に実行する処理を記述する。 --> <% end %>送信したフォームの情報にサインインしているユーザーの情報を追加したい場合…
_controller.rbclass PostsController < ApplicationController private def post_params params.require(:post).permit(:title, :content).merge(user_id: current_user.id) # form_with を使用して送信される情報を取得するストロングパラメータに .merge メソッドを使用して、current_user (現在ログインしているユーザー) の ID を結合させる。 end end