- 投稿日:2020-02-14T23:45:37+09:00
[Rails]gem devise インストール
deviseとは
deviseとはrailsで作ったwebアプリケーションに簡単に認証機能を実装できるgemのことです。認証機能はログイン、ログアウト機能の事です。
deviseをインストール
1. Gemをインストールするために、Gemfileに追記
基本的に1番下に記載するのが無難です。
gem 'devise'
以下はNG例です。
上記の記述だとdevelopment環境から、テストや本番環境に移行していくので、その際に対応できなくなります。2. Gem記載後、実際にdeviseのインストール
bundle install
を実行してgemを読み込みます。3. deviseが入ったか確認
Gemfile.lockというファイルにはインストールされたgemが一覧表示されているので、ここに'devise'が入っているか確認します。
4. rails g devise:installを実行
deviseの設定ファイルをrailsアプリケーションにインストールするためにbundle installの他にもdevise用のインストールコマンドを実行します。
rails g devise:install
Userモデルを作成する場合
deviseで使用する場合は、通常のrails g modelではなく以下のコマンドを実行します。
rails g devise user
※必要に応じてマイグレーションファイルやmodels/user.rbを訂正しましょう。
マイグレーションを実行
userモデルをもとに、データベースを作成します。
rails db:migrate
コマンドミスを起こした場合
rails d model user
を実行します。
訂正後、rails db:rollback
を実行します。ビューファイルの作成
rails g devise:views users
これでapp>views>users ←ここにファイルができます。
- 投稿日:2020-02-14T23:19:15+09:00
schema.rbにマイグレーションファイルが反映されない!
開発環境
ubuntu(WSL)
Rails 5.2
Postgresql想定エラー内容
ActionView::Template::Error (PG::UndefinedColumn: ERROR: column tasks.user_id does not exist LINE 1: SELECT "tasks".* FROM "tasks" WHERE "tasks"."user_id" = $1 O...原因
一概には言えないですが、おそらく
rails:db migrate
した後にマイグレーションファイルを書き換えている。対処法
rails db:migrate:status
で反映されているか確認する。
upは反映済み。downは未反映。Status Migration ID Migration Name -------------------------------------------------- up 20200213054056 Create users up 20200214132021 Add user id to tasks
rails db:migrate:rollback
で戻す。
マイグレーションファイルを書き換えて再び、rails db:migrate
を実行する。参考文献
- 投稿日:2020-02-14T21:06:34+09:00
【Rails】中級者になるためのリファクタリング
Railsのリファクタリングの記事は、良記事がたくさんあります。
でも「初心者向け」を謳っているにしては項目が多くて、いきなり全部を意識するのは無理だなってなりました。初心者向けって謳い文句の記事に、自分のできていないことがたくさん書かれていると「お前は初心者以下だ」って言われているみたいでちょっと嫌な気持ちになりますね。
他の方が書いた記事の中から、私がまず意識しようと思ったことをピックアップしてまとめようと思います。
controllerを薄く、modelを厚く
可能な限り処理をメソッドとして切り出して、controllerを薄くします。
modelがFatになることは、最初は目をつぶります。viewの中の処理をhelperに移す
viewの中に処理がゴチャゴチャと書かれていると、コードが混沌としてしまうので。
パーシャルをどんどん使う
パーシャルを使って、可読性と再利用性を上げます。
jsはjsファイルに
ページごとのjsファイルを作り、そこに書く。
繰り返し使う文字列をlocaleに定義する
コードをDRYに。時刻のフォーマット等もlocaleを使い、
strftime
は基本使わない。コードの行数を減らす
基本的に以下の記事からのピックアップです。超良記事なのでまだ読んでいない人はぜひ。
[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか最初はとっつきにくくても、短く書ける記法はどんどん使って慣れていくべき。慣れたら難しくないものも多そうだし、他の人が書いたコードを理解する能力も上がる。
とはいえ全部いきなりは大変なので、まずは以下を意識する。なるべくネストしない
早めにreturnで返すなど、出来るだけネストを減らすことを意識します。
後置if
send_mail_to(user) if user.active?三項演算子
user.admin? ? "I appreciate for that." : "Thanks"ぼっち演算子
#if parent.children && parent.children.singleton? if parent.children&.singleton?||=でnilだった場合のみ代入
@twitter_client ||= Twitter::REST::Client.newその他書き方
if + notではなく、unless
user.destroy unless user.active?条件にorとかandが含まれる時は複雑になるので
if
を使う戻り値を返すときにreturnを使わない
def build_message(user) message = 'hello' message += '!!' if user.admin? #return message message end+ではなく#{ }
#"Hello, " + user.name + "!" "Hello, #{user.name}!"%w( )、%i( )
#actions = ['index', 'new', 'create'] actions = %w(index new create) #actions = [:index, :new, :create] actions = %i(index new create)いつかやる
・他の便利な文法いろいろ
・RESTなcontrollerを意識する
・Concern(controllerで共通で使う処理をまとめるやつ)を使う
・デコーダー?ViewModel?
・サービスクラス?参考
[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか
脱Rails初心者のためのリファクタリングガイド
実務で学んだRailsの設計・リファクタリング
- 投稿日:2020-02-14T20:06:11+09:00
【Rails】localeの使い方
localeとは
もともとは多言語化用の言語ファイル。
多言語化以外にも、何度も使う文言を一限管理するために使われる。
住所、会社名、時間をフォーマットする時の形式、今日の日付を出力する時の形式などを管理する。基本
config/application.rb
でデフォルトの言語を指定config/application.rbconfig.i18n.default_locale = :ja
config/locales
以下にlocaleファイルを作成config/locales/ja.ymlja: hello: Hello World company: name: サンプル株式会社 address: 〒231-0001 神奈川県横浜市中区新港2丁目7−1viewから呼び出す<%= t('hello') %> <!-- Hello World --> <%= t('company.name') %> <!-- サンプル株式会社 -->modelから呼び出すI18n.t('hello') #=> 'Hello World' I18n.t('company.name') #=> 'サンプル株式会社'ポイント
- 呼び出し時、
ja
の部分は書かない- localeファイルの名前は何でも良い。
- viewから呼び出す時は
I18n.
の部分を省略できる。- 同じキーのデータが複数あった場合、後に定義したデータで上書きされる
日付や時刻のフォーマットを定義する
config/locales/ja.ymlja: date: formats: default: "%Y/%m/%d" long: "%Y年%m月%d日(%a)" short: "%m/%d" time: formats: default: "%Y/%m/%d %H:%M:%S" long: "%Y年%m月%d日(%a) %H時%M分%S秒 %z" short: "%y/%m/%d"I18n.l(Date.today) #=> '2020/02/14' I18n.l(Date.today, format: :long) #=> '2020年02月14日(金)' I18n.l(Time.zone.now) #=> '2020/02/14 18:34:25' I18n.l(user.created_at, format: :short) #=> '20/02/14'ポイント
- DateクラスやTimeクラスの値をセットすると、
date
やtime
に定義した形でフォーマットするformat
を省略するとdefault
の内容が適用される。l
はlocalizeの略。ちなみにt
はtranslateの略。created_at
やupdated_at
をI18n.l()
でラップすると、time
に定義したフォーマットで出力される。変数を渡す
config/locales/ja.ymlja: airmax: "NIKE AIRMAX %{year}"I18n.t('airmax', year: 95) #=> 'NIKE AIRMAX 95'モデルの情報を定義する
主にエラーメッセージ中のモデル名や属性名を日本語化する目的で。
config/locales/ja.ymlja: activerecord: # モデル名 models: user: ユーザー item: アイテム # モデルごとの属性 attributes: user: name: 名前 address: 住所 item: power: パワー # 全モデル共通の属性 attributes: created_at: 作成日時 updated_at: 更新日時階層分け
・スッキリ管理する
・conflictのリスクを減らす
ために、localeファイルを階層分けしてたくさん作ることも多い。階層分けをする場合
config.i18n.load_path
の設定をすることで、config/locale
直下のファイル以外も参照できるように設定します。config/application.rbconfig.i18n.default_locale = :ja #↓追加 config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]rails-i18n
rails-i18n
というgemを使うと、よく使う単語を全部一気に導入できます。多言語対応をする時には有用だと思いますが、日本語だけの場合はわざわざgemを入れなくても、上記のページに書いてある内容を全部コピペすれば良い気がします。
参考
- 投稿日:2020-02-14T18:36:16+09:00
RailsでFontAwesomeの導入〜大きさを変えるまで
はじめに
railsでFontAwesomeを使いたいと思い調べていたところ、
大きさまで変える記事が見当たらなかったため投稿してみました。実行環境
Ruby : 2.6.3
Rails : 5.2.4
slim : 4.0.1
font-awesome-sass : 5.12.0
上記の環境で実装いたしました。FontAwesomeの導入
Gemfileに以下を記述
Gemfilegem 'font-awesome-sass'gemをインストール
bundle install/app/assets/stylesheets/application.css
を
/app/assets/stylesheets/application.scss
に変更するmv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss/app/assets/stylesheets/application.scssに以下を記述
application.scss@import "font-awesome-sprockets"; @import "font-awesome";上記の順番通りに記述したことで、FontAwesomeが使えるようになった。
実行結果
font-awesome-sassがインストールされたことにより、ヘルパーメソッドが使えるようになりました。
このメソッドを使うことでアイコンを表示させます。~.html.slim= link_to "#" do = icon 'fab', 'amazon-pay'これでアイコンが表示されました。
今回使用したアイコン大きさを変更する
上記で用いたヘルパーメソッドを用いることによって好みの大きさに変更することも可能です。
~.html.slim= link_to "#" do = icon 'fab', 'amazon-pay fa-3x'このメソッドは次のように構成されています。
icon 'スタイル名', 'アイコン名 (大きさ指定)'大きさの指定をしない場合は、アイコン名のみを記述し、
大きさ指定をする場合は、アイコン名の後にスペースをあけ、'fa-(サイズ)'で好きな大きさに変更することができます。サイズに関しては公式サイトをご覧ください。
Font Awesome最後に
初めて記事を投稿してみました。
分かりやすい記事になったかは不安ですが、誰かの助けになれば幸いです。
- 投稿日:2020-02-14T16:22:25+09:00
RSpecでFactoryBotから複数のインスタンスをまとめて作成する【create_listを使用】
RSpecテストを書いているときに、複数のインスタンスをまとめて作れる便利メソッド
create_list
をご紹介します。
例えば下記のように
note
のファクトリが定義されているとします。factory/notes.rbFactoryBot.define do factory :note do title { 'sample-note' } description { 'sample-description' } end endテストで
note
インスタンスを5つ作りたいと思ったとき、下記のように1つずつ作るのは大変です。spec/system/xxx_spec.rbRSpec.describe 'yyyy' do let(:note1) { create(:note) } let(:note2) { create(:note) } let(:note3) { create(:note) } let(:note4) { create(:note) } let(:note5) { create(:note) } ... endここで登場するのが
create_list
です。
これを使えば、まとめてnoteインスタンスを作成することが可能です。spec/system/xxx_spec.rbRSpec.describe 'yyyy' do notes = create_list(:note, 5) ... end第1引数に元になるファクトリ、第2引数に作成する数を指定します。
(notes =
の部分は無くても可)ちなみに属性の一部を上書きして作成することも可能です(下記参照)。
spec/system/xxx_spec.rbRSpec.describe 'yyyy' do notes = create_list(:note, 5, title: 'Hello, World') ... end
以上です。
- 投稿日:2020-02-14T15:14:31+09:00
【Rails】wicked pdfの導入方法、ハマったところと対応
導入方法
Gemfilegem 'wicked_pdf' gem 'wkhtmltopdf-binary'$ bundle install $ rails g wicked_pdfconfig/initializers/wicked_pdf.rbWickedPdf.config = { :exe_path => "#{Gem.loaded_specs['wkhtmltopdf-binary'].full_gem_path}/bin/wkhtmltopdf" }ここで一度サーバーを再起動
pdfs_controller.rbdef bill respond_to do |format| format.html format.pdf do render pdf: 'bill', layout: 'pdf', encording: 'UTF-8', template: 'pdfs/bill' end end endviews/layouts/pdf.pdf.erb<!DOCTYPE html> <html> <head> <meta charset='utf-8' /> </head> <body> <div id="content"> <%= yield %> </div> </body> </html>views/pdfs/bill.pdf.erb<p>請求書</p> <style> p { font-size: 20px; } </style>routes.rbget 'pdf/bill.pdf', to: 'pdfs#bill' #get 'pdf/bill'と書いて、`pdf/bill.pdf`にアクセスしても動くハマったところと対応
フォントサイズが全部小さい
普段のノリでフォントサイズを指定すると、全部小さく表示されます。
フォントサイズを大きい数値に変更して対応。本番環境のみ、AssetPilelineのコンパイルエラー
レイアウト内のCSS、JS、mysite.jpg読み込み部分を全て削除。
CSSは全部インラインで記述。(別プロジェクトを作り、Sassで書き、コンパイルしたものをコピペする)本番環境のみ、日本語が表示されない
本番のサーバーに日本語フォントをインストールして対応
$ yum install -y ipa-gothic-fonts $ yum install -y ipa-mincho-fontsその他注意点
- flexboxが使えない
- 画像、CSS、JS等のパスの指定方法が特殊
通常 wicked_pdf cssファイル stylesheet_link_tag wicked_pdf_stylesheet_link_tag jsファイル javascript_include_tag wicked_pdf_javascript_include_tag iamgeファイル image_tag wicked_pdf_image_tag 参考
Rails で Wicked PDF 使って PDF を出力してみた ( 日本語もバッチリ )
railsでwicked_pdfの使い方
- 投稿日:2020-02-14T11:59:32+09:00
【Rails】Modelで定義した定数に他クラスやViewからアクセスする方法
表題の通り、定数にアクセスできずに困った人のための記事です。
結論
Model名::定数名とすればOKです。
解説
下記のUserクラスがあるとします。
models/user.rbclass User < ActiveRecord::Base MAX_NUMBER = 10 ... endViewから参照するには、下記のようにします。
views/xxx.html.erb最大値は#{User::MAX_NUMBER}です。
これが下記のようになっていると、views/xxx.html.erb最大値は#{MAX_NUMBER}です。↓
uninitialized constant ActionView::CompiledTemplates::MAX_NUMBERそんな定数は無いと怒られてしまいます。
以上です!
- 投稿日:2020-02-14T11:59:32+09:00
【Rails】Modelで定義した定数にViewからアクセスする方法
表題の通り、定数にアクセスできずに困った人のための記事です。
結論
Model名::定数名とすればOKです。
解説
下記のUserクラスがあるとします。
models/user.rbclass User < ActiveRecord::Base MAX_NUMBER = 10 ... endViewから参照するには、下記のようにします。
views/xxx.html.erb最大値は#{User::MAX_NUMBER}です。
これが下記のようになっていると、views/xxx.html.erb最大値は#{MAX_NUMBER}です。↓
uninitialized constant ActionView::CompiledTemplates::MAX_NUMBERそんな定数は無いと怒られてしまいます。
以上です!
- 投稿日:2020-02-14T11:52:35+09:00
ActiveRecordのトランザクションのネストに気をつけること
- 確認した環境
- Ruby 2.5.1
- Rails 5.2.1
- MySQL 5.7.27
腕試しに以下のスクリプトを実行した場合、最終行の
User.first.name
は何が得られるか考えてみてください.User.first.update!(name: 'Alice') ActiveRecord::Base.transaction do User.first.update!(name: 'Bob') ActiveRecord::Base.transaction do User.first.update!(name: 'Carol') raise ActiveRecord::Rollback end end User.first.name
正解はここをクリック
User.first.name
の結果は Carol になります.
正解しましたか?
正解する人もいると思いますが直感と違うかと思います.
TL;DR
- 可能ならトランザクションをネストしない設計する
- トランザクションをネストする設計の際は
requires_new: true
を使う
- 付けないと思いのよらないゴミができる可能性がある
検証
分かりやすくするため、SQLをコメントに加えました.
User.first.update!(name: 'Alice') # BEGIN # UPDATE `users` SET `name` = 'Alice' WHERE `users`.`id` = 1 # COMMIT ActiveRecord::Base.transaction do # BEGIN User.first.update!(name: 'Bob') # UPDATE `users` SET `name` = 'Bob' WHERE `users`.`id` = 1 ActiveRecord::Base.transaction do User.first.update!(name: 'Carol') # UPDATE `users` SET `name` = 'Carol' WHERE `users`.`id` = 1 raise ActiveRecord::Rollback end end # COMMIT User.first.name # => 'Carol'requires_new を使った場合
いくつかのRDBにはトランザクションにSAVEPOINTをサポートしているものがあります.
このSAVEPOINTを利用するにはrequires_new
を指定することで有効になり直感に近い挙動をする様になります.User.first.update!(name: 'Alice') # BEGIN # UPDATE `users` SET `name` = 'Alice' WHERE `users`.`id` = 1 # COMMIT ActiveRecord::Base.transaction do # BEGIN User.first.update!(name: 'Bob') # UPDATE `users` SET `name` = 'Bob' WHERE `users`.`id` = 1 ActiveRecord::Base.transaction(requires_new: true) do # SAVEPOINT active_record_1 User.first.update!(name: 'Carol') # UPDATE `users` SET `name` = 'Carol' WHERE `users`.`id` = 1 raise ActiveRecord::Rollback end # ROLLBACK TO SAVEPOINT active_record_1 end # COMMIT User.first.name # => 'Carol'
- 投稿日:2020-02-14T11:29:24+09:00
ぼっち演算子
Deviseを使ったRailsのコードがあるとします。
これはDeviseを使用したときのcurrent_userに対して、nicknameカラムに
あるデータを取得して@nicknameに代入することを意図したものです。
@nickname = current_user.nickname
ただし、ログインしないときにこれを実行するとnilに対してメソッドを使おうとしてエラーになってしまいます。
これを回避できる記述がRuby2.3からできるようになりました。
それがどのような記述か、またそれはどのような動きをするのかについて説明していきます。解答
@nickname = current_user&.nickname&はsafe navigation operator、 lonely operator(ぼっち演算子)などと呼ばれる演算子です。
メソッドに続けて記述すると、そのメソッドがnilでなかった場合のみ右辺のメソッドが実行されます。
もしnilだった場合は全ての演算結果としてnilを返します。つまり@nicknameにnilが代入されます。
とても使い勝手の良い演算子のため、覚えて活用していきましょう。
なお、ぼっち演算子という命名は、&の記号が一人ぼっちで膝を抱えている人に見えるところからきています。
<参考記事>
・https://kossy-web-engineer.hatenablog.com/entry/2018/09/20/060701
・https://ja.wikipedia.org/wiki/Null%E6%9D%A1%E4%BB%B6%E6%BC%94%E7%AE%97%E5%AD%90
・https://matt-note.hatenadiary.jp/entry/2018/11/14/083307
- 投稿日:2020-02-14T11:26:15+09:00
Railsのform_forで、bootstrap4を使ってフォームを横並びにする方法
概要
Railsのform_forを使っている箇所で、フォームを横並びにするのに少しハマったので、共有させていただきます。
環境
ruby 2.6.3 Rails 5.1.6 bootstrap 4.4.1
方法
bootstrapのグリッドシステム(rowとcol-(数字))を使う。
フォームをdiv.rowで囲って、横並びにしたい要素をdiv.col-で囲む。
(上記少し誤解を与える表現ですが、下記注意点をご参照ください)注意点
form_forメソッドの外側でなく、内側にdiv.rowを配置する。
具体的な方法(OKパターン)
home.html.erb<%= form_for(:session, url: login_path) do |f| %> <div class="row"> <div class="col-2"> <div class="form-group"> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> </div> </div> <div class="col-2"> <div class="form-group"> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> </div> </div> <div class="col-2 align-self-end"> <div class="form-group"> <%= f.submit "ログイン", class: 'btn btn-primary' %> </div> </div> </div> <% end %>ダメなパターン
home.html.erb<div class="row"> <%= form_for(:session, url: login_path) do |f| %> <div class="col-2"> <div class="form-group"> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> </div> </div> <div class="col-2"> <div class="form-group"> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> </div> </div> <div class="col-2 align-self-end"> <div class="form-group"> <%= f.submit "ログイン", class: 'btn btn-primary' %> </div> </div> <% end %> </div>以上です。
その他
Qiitaにちゃんとした(ちゃんとしてますか!?)投稿をするのが初めてでした。
ご指摘あればぜひお願いいたします。
- 投稿日:2020-02-14T11:15:45+09:00
ルーティングを設定してCSVデータをダウンロードする方法
目的
- Qiitaの記事に大まかな流れをテンプレート化しておき、作業効率を上げる。
- 今までの実装では
send_data
しか使ったことなかったのでメモ前提条件
- ruby 2.6.0
- ruby 5.2.2
手順
- routes.rbにCSVダウンロード用のルーティングを設定する
- コントローラーに変数を定義、その他諸々を設定
- 出力データを作成(アクション名.csv.ruby)
- CSVダウンロードボタンを設定したいviewファイルに書く
※コード内容は適当
1. routes.rbにCSVダウンロード用のルーティングを設定する
config/routes.rbresources :card_infos do collection do # デフォルト形式をcsvに設定 get :csv_download, defaults: { format: 'csv' } end end
Helper HTTP Verb Path Controller#Action csv_download_card_infos_path GET /card_infos/csv_download(.:format) card_infos#csv_download {:format=>"csv"} 2. コントローラーに変数を定義やその他諸々を設定
app/controllers/card_infos_controller.rbclass CardInfosController < ApplicationController def csv_download @cards = CardInfo.all # CSVダウンロードファイルのヘッダーを生成する create_csv_file_header("card_info_#{ Time.zone.now.strftime('%Y%m%d') }") end end共通化メソッド# CSVダウンロードファイルのヘッダーを生成する def create_csv_file_header(file_name) file_name = ERB::Util.url_encode(file_name) if (/MSIE/ =~ request.user_agent) || (/Trident/ =~ request.user_agent) headers['Content-Disposition'] = "attachment; filename=\"#{file_name}.csv\"" end3. 出力データを作成(アクション名.csv.ruby)
※viewディレクトリ配下に設置する
app/views/card_infos/csv_download.csv.rubyrequire 'csv' columns = %w( 番号 会社 子会社 カード種類 カード会社 管理区分 ) # encoding等のoptionは仕様によって変えてください CSV.generate(encoding: Encoding::SJIS, row_sep: "\r\n", force_quotes: true) do |csv| csv << columns @cards.each_with_index do |card, number| csv << [ number + 1, card.company.parent_company.company_name, card.company.company_name, card.card_type.card_type_i18n, card.card_type.card_company.card_company_name, card.management_type_i18n, ] end end4. CSVダウンロードボタンを設定したいviewファイルに書く
(例)app/views/card_infos/index.html.erb<%= link_to csv_download_card_infos_path, class: "btn_blue btn_big csv_dl", download:"", style: "padding: 8px 25px; font-family: Arial;" ) do %> <i><img src="<%= asset_path 'icon_download.svg' %>" alt="CSVダウンロード"></i>CSVダウンロード <% end %>??変更するファイル
. ├── app | ├── controllers | | | | | └── card_infos_controller.rb ②アクションを設定 | | | | | | | └── views | | | └── card_infos | | | └── csv_download.csv.ruby ③出力ファイルを設定 | | ├── config | | └── routes.rb ①ルーティングを設定 ④ViewファイルにCSVダウンロードボタンを設置
関連URL
- 投稿日:2020-02-14T11:15:45+09:00
ルーティングを設定してCSVデータのダウンロード(出力)を実装する方法
目的
- Qiitaの記事に大まかな流れをテンプレート化しておき、作業効率を上げる。
- 今までの実装では
send_data
しか使ったことなかったのでメモ前提条件
- ruby 2.6.0
- ruby 5.2.2
手順
- routes.rbにCSVダウンロード用のルーティングを設定する
- コントローラーに変数を定義、その他諸々を設定
- 出力データを作成(アクション名.csv.ruby)
- CSVダウンロードボタンを設定したいviewファイルに書く
※コード内容は適当
1. routes.rbにCSVダウンロード用のルーティングを設定する
config/routes.rbresources :card_infos do collection do # デフォルト形式をcsvに設定 get :csv_download, defaults: { format: 'csv' } end end
Helper HTTP Verb Path Controller#Action csv_download_card_infos_path GET /card_infos/csv_download(.:format) card_infos#csv_download {:format=>"csv"} 2. コントローラーに変数を定義やその他諸々を設定
app/controllers/card_infos_controller.rbclass CardInfosController < ApplicationController def csv_download @cards = CardInfo.all # CSVダウンロードファイルのヘッダーを生成する create_csv_file_header("card_info_#{ Time.zone.now.strftime('%Y%m%d') }") end end共通化メソッド# CSVダウンロードファイルのヘッダーを生成する def create_csv_file_header(file_name) file_name = ERB::Util.url_encode(file_name) if (/MSIE/ =~ request.user_agent) || (/Trident/ =~ request.user_agent) headers['Content-Disposition'] = "attachment; filename=\"#{file_name}.csv\"" end3. 出力データを作成(アクション名.csv.ruby)
※viewディレクトリ配下に設置する
app/views/card_infos/csv_download.csv.rubyrequire 'csv' columns = %w( 番号 会社 子会社 カード種類 カード会社 管理区分 ) # encoding等のoptionは仕様によって変えてください CSV.generate(encoding: Encoding::SJIS, row_sep: "\r\n", force_quotes: true) do |csv| csv << columns @cards.each_with_index do |card, number| csv << [ number + 1, card.company.parent_company.company_name, card.company.company_name, card.card_type.card_type_i18n, card.card_type.card_company.card_company_name, card.management_type_i18n, ] end end4. CSVダウンロードボタンを設定したいviewファイルに書く
(例)app/views/card_infos/index.html.erb<%= link_to csv_download_card_infos_path, class: "btn_blue btn_big csv_dl", download:"", style: "padding: 8px 25px; font-family: Arial;" ) do %> <i><img src="<%= asset_path 'icon_download.svg' %>" alt="CSVダウンロード"></i>CSVダウンロード <% end %>??変更するファイル
. ├── app | ├── controllers | | | | | └── card_infos_controller.rb ②アクションを設定 | | | | | | | └── views | | | └── card_infos | | | └── csv_download.csv.ruby ③出力ファイルを設定 | | ├── config | | └── routes.rb ①ルーティングを設定 ④ViewファイルにCSVダウンロードボタンを設置
関連URL
- 投稿日:2020-02-14T11:08:59+09:00
[Rails] scriptタグ内でRuby/Railsのメソッドを使用する際のescape_javascriptについて
この記事を書くきっかけ
jQueryを書いていると、scriptタグ内でRailsのメソッド(正確にはapplication_helper内のメソッド)を使用したいときがあります。
正しい書き方をしないと正確に呼び出せないため、失敗した書き方と成功した書き方をまとめます。前提
current_userの属性によってpathを切り替えるメソッドを
def hogehoge_path_for
とし、application_helper.rbに定義します。application_helper.rbdef hogehoge_path_for if ... hoge_path else hogehoge_path end endこれをとあるviewのscriptタグ内で呼び出します。
let path = hogehoge_path_forの返り値
としたいです。失敗例1
あるview<script> let path = <% hogehoge_path_for %>; </script>普通はこう考えるはずですが、これだと呼び出せません。
失敗例2
あるview<script> let path = <% hogehoge_path_for %>; </script>これも呼び出せません。
失敗例3
escape_javascript
というメソッドを使用します。
なお、これはaliasとしてj
の使用が許されています。あるview<script> let path = <% escape_javascript hogehoge_path_for %>; </script>上記は下記と同じです。
あるview<script> let path = <% j hogehoge_path_for %>; </script>どちらも失敗します。
失敗例4
=をつけます。
あるview<script> let path = <%= escape_javascript hogehoge_path_for %>; </script>上記は下記と同じです。
あるview<script> let path = <%= j hogehoge_path_for %>; </script>これもどちらも失敗します。
失敗例5
=を外して、
''
で囲います。あるview<script> let path = '<% escape_javascript hogehoge_path_for %>'; </script>上記は下記と同じです。
あるview<script> let path = '<% j hogehoge_path_for %>'; </script>これもどちらも失敗します。
成功例
=
をつけて''
で囲います!あるview<script> let path = '<%= escape_javascript hogehoge_path_for %>'; </script>上記は下記と同じです。
あるview<script> let path = '<%= j hogehoge_path_for %>'; </script>
これで無事呼び出すことができました。
- 投稿日:2020-02-14T09:01:04+09:00
Ruby初心者の「結局インスタンスメソッドって何ですか?」にエンジニア歴30年のベテランさん超絶わかりやすいアンサー!!!
結論
インスタンスメソッドとは:インスタンスが(に)使えるメソッド(にくっつくメソッド)
助詞に関しては、インスタンスを主語として考えるか目的語として考えるかの違いです。図で表すとこんな感じ
インスタンスはいわゆる勇者。その勇者の剣がメソッド。つまり「勇者の剣」=インスタンスメソッドなわけだ!
僕の誤解を招いた表現その1
インスタンスメソッドとはインスタンスを含む変数である。*間違い
僕の誤解を招いた表現その2
インスタンス変数にくっつくメソッドである *惜しい、変数ではなくインスタンス自身にくっつくのがインスタンスメソッド
そもそもインスタンスって?
インスタンス化
クラス(クラスがわからない人は下に説明あります!)はnewすると初期化(インスタンスを作成する方法は他にもあるが基本はnew)し、実体化することができます。実体化したものをインスタンスと呼びます。
インスタンス変数
インスタンスは自身の中に複数の値を所有することができます。Rubyでは @ で始まる名前がインスタンスが所有する変数、インスタンス変数です。インスタンスが持つというニュアンスが大切。インスタンスを指し示す変数ではないですよ!
そもそもクラスってなんぞや?
1と2どちらも同義ですが、自分にわかりやすい方で構いません!
1. 新しい型を作る方法(型ってのは設計図みたいなものですね。)
2. データと処理のまとまりを部品としてわかりやすく定義する方法
- 投稿日:2020-02-14T08:33:10+09:00
組み合わせ爆発を回避せよ!Rails初心者エンジニアの工夫
初心者である私はif~elseの形に慣れ過ぎていた
最初は下記のように書いていた。(statusは絶対に値が入っているので1では省略)
1
if params[:title].present? if params[:price_gteq].present? && params[:price_lt].present? @products = Product.where("price>=? AND price<=?", "#{params[:price_gteq]}", "#{params[:price_lt]}").where(status: params[:status]).where(title: params[:title]) else @products = Product.where(title: params[:title]) end else if params[:price_gteq].present? && params[:price_lt].present? @products = Product.where("price>=? AND price<=?", "#{params[:price_gteq]}", "#{params[:price_lt]}").where(status: params[:status]).where(title: params[:title]) else @products = Product.all end endもっと簡単にかけるくない?と思いelseを抜いた。しかしまだゴールではない
2
@products = Product.all @products = Product.where(status: params[:status]).where(title: params[:title]) if params[:title].present? @products = Product.where("price>=? AND price<=?", "#{params[:price_gteq]}", "#{params[:price_lt]}").where(status: params[:status]) if params[:price_gteq].present? && params[:price_lt].present? @products = Product.where("price>=? AND price<=?", "#{params[:price_gteq]}", "#{params[:price_lt]}").where(status: params[:status]).where(title: params[:title])if params[:price_gteq].present? && params[:price_lt].present? && params[:title].present?まだまだ綺麗にかけるぞ!と思い、さらに絞り込む。ここで考えないといけないのが
ActiveRecord::Relationは、where などで演算した後も ActiveRecord::Relation を返すということ
一瞬はてなマークが頭に浮かぶと思います。簡単にいうと、whereなどのActiveRecord::Relationは同じ型を返し続ける性質があるという。そのことを踏まえて書いたコードがこちら(ゴール)
3
@products = Product.all @products = @products.where(title: params[:title]) if params[:title].present? @products = @products.where(status: params[:status]) if params[:status].present? @products = @products.where("price>=? AND price<=?", "#{params[:price_gteq]}", "#{params[:price_lt]}") if params[:price_gteq].present? && params[:price_lt].present?###3番のゴールは雰囲気はこれと同じ。三番はこれを場合分けしている### @products = @products.where(title: params[:title]).where(status: params[:status]).where("price>=? AND price<=?", "#{params[:price_gteq]}", "#{params[:price_lt]}")今回のポイント
- 条件分岐は「存在するときだけ発動する」みたいなニュアンス
- ActiveRecord::Relationは同じ型を返し続ける
- 投稿日:2020-02-14T02:06:25+09:00
Rails初心者が知っておきたい基礎知識|gem、Bundler など…
この記事では、《Rails初心者が知っておきたい基礎知識》について、
僕が学習した内容をまとめています。
- gem とは…?
- Gemfile とは…?
- Gemfile.lock とは…?
- Bundler とは…?
こういった疑問についてまとめています。
※本記事は、自分で学習したことのまとめ用として書いています。
尚、解説で誤った点があれば、スローして頂ければ喜んでキャッチしますのでお願い致します。gem とは…?
『gem』は・・・
Rubyのライブラリ(パッケージともいいます)です。
『ライブラリ』とは…
プログラムの部品で、便利な機能をひとまとめにしたものです。ライブラリを利用することで、自分で1からコードを書くことなく機能を実装することができるので、効率的に開発することが可能です。
Rubyのgemには便利なものがたくさんあり、例えば…
- Rails(Webフレームワーク)
- Devise(ログイン機能)
- Kaminari(ページネーション)
- unicorn(アプリケーションサーバ)
- Active Admin(管理画面)
などがあります。
gemを使うことでログイン機能やページネーションといった機能も、簡単に実装可能です。Gemfile とは…?
『Gemfile』は・・・
gemをインストールするための『設計書』のようなもので、基本的にこの
Gemfile
に自分のアプリケーションに必要なgemを記述します。Gemfile.lock とは…?
『Gemfile.lock』は・・・
gemをインストールした後の『ログ、記録』のようなもので、インストールしたgemの一覧とバージョンが記載されています。
【比較】Gemfile と Gemfile.lock の違い
Gemfile Gemfile.lock 更新方法 手動 自動 更新タイミング コマンド実行前 コマンド実行後 内容 インストールするgem インストールしたgem 【余談】なぜ Gemfile.lock が必要なのか…?
gemは、インストールした時期によってバージョンが変わってしまう可能性があるため…
例えば、本番環境と開発環境でインストールされるgemのバージョンが異なってしまう可能性があります。しかし・・・
Gemfile.lock
が使用するgemのバージョンを管理してくれるため、仮にgemがアップデートされても、使用するgemのバージョンは変更させないということが可能になります。ちなみに・・・
Gemfile.lock
を更新したい時は、bundle update
を使います。Bundler とは…?
『Bundler』は・・・
gemを管理するためのgemで、Bundlerを使用することで…
bundle installbundle updateなどのコマンドが使用できるようになります。
gem同士は関連し合っていることが多いので、実際は
Gemfile
に書いてあるgemの他にも、gemが必要になります。そこで・・・
Bundler
は、それらも自動でインストールし、Gemfile.lock
に記述してくれます。
Bundler
は、特定のRailsアプリケーションに必要なgemパッケージをリストアップし、複数のコンピュータ間で簡単に同期が取れるようにするものです。例えば・・・
上記の図のように開発者Bさんが、開発者AさんからRailsアプリのソースコードを受け取ったとします。
この時、Bさんは
bundle install
を実行するだけで、必要なgemをインストールすることができ、簡単に環境を構築できます。【一覧】 よく使う Bundlerコマンド のオプション
コマンド 概要 bundle init Gemfileを生成 bundle install Gemfileに記述したgemをインストール bundle update インストール済みのgemのバージョンを更新 bundle list インストール済みのgemを一覧表示する bundle exec Bundlerでインストールしたgemを使用して、
コマンドを実行【コマンド】 bundle install とは…?
bundle install上記を実行すると・・・
Railsは、
Gemfile.lock
を元にgemのインストールを行います。この時…
『
Gemfile.lock
に記述されていなくて、且つGemfile
に記述されているgem』がある場合、『該当するgem』と『該当するgemに関連するgem』をインストールした後、
Gemfile.lock
を更新します。反対に、
Gemfile.lock
に記述されていれば・・・そこに記述されたgemを見て、それがGemfileの内容に矛盾していない限り、
Gemfile.lock
の内容に従いインストールします。【コマンド】 bundle update とは…?
bundle update上記を実行すると・・・
Bundlerは、
Gemfile
を元にgemのインストールを行い、その後Gemfile.lock
を更新します。【余談】上記2つのコマンドの使い分けを少し解説
bundle update
は・・・その言葉通り、gemのバージョンを更新する時に使用します。
なぜなら・・・
bundle install
コマンドでは、条件に矛盾が生じない限りGemfile.lock
に存在するgemに関しては、更新作業を行わないからです。※
bundle update
は、本番環境で安易に実行しないように注意しましょう。場合によっては、gemのバージョンにズレが発生し、クラッシュする可能性があります。ですので・・・
bundle update
は、必ずローカル環境で実行してください。また、
bundle install
に関しては・・・
Gemfile
に新しくgemを記述した際に使用します。
- 投稿日:2020-02-14T00:15:45+09:00
RSpec で ある要素のみが入った配列かどうかを確認したいときは contain_exactly を使う
概要
a,b,c のリソースがあるときに、a,c のみが順番は関係なく返されることをテストしたいときには、contain_exactly が便利です。
コード
let!(:user_a) { create(:user, name: 'a') } let!(:user_b) { create(:user, name: 'b') } let!(:user_c) { create(:user, name: 'c') } it 'returns ac users do expect(User.hoge).to contain_exactly(user_a, user_c) end順番もテストするときは素直に eq matcher で配列を使う。
it 'returns ac users do expect(User.hoge).to eq [user_a, user_c] end参考:
contain_exactly
matcher
https://relishapp.com/rspec/rspec-expectations/v/3-9/docs/built-in-matchers/contain-exactly-matcher