Rails
フォーム送信中にダブルクリックを止める
Rails submitタグにつけておきたいdisable_withオプション
タグに直書きする時は data-disable-with="送信中"
コーディングパターン
実務で学んだRailsのコーディングパターン - Qiita
Rails を始めてから「知って良かった」と思った"Rail"10選 - Qiita
パーシャルの書き方
<%= render "menu" %>同階層の_menu.html.erb
<%= render "shared/menu" %>app/views/shared/_menu.html.erb
rubyXLを使ったxlsx出力
code:rb
# respond_toを利用して、xlsxを求められたらviewを切り替える
respond_to do |format|
format.html
format.xlsx do
# rubyXLはRailsのView層にコンバート頑張って作る
workbook = RubyXL::Workbook.new
sheet = workbook.first
sheet.add_cell(0,0, "Hello Wrold!")
send_data workbook.stream.read, filename: 'test.xlsx', type: :xlsx
end
end
axlsx_railsを使ったxlsx出力
straydogstudio/axlsx_rails
axlsx_rails を用いて Excel のスプレッドシートを生成する - Qiita
wicked_pdfを使ったPDF出力
mileszs/wicked_pdf
Rails で Wicked PDF 使って PDF を出力してみた ( 日本語もバッチリ ) - Qiita
railsでwicked_pdfの使い方 - Qiita
Gemインストール
code:gemfile
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary'
コンフィグファイル作成
rails g wicked_pdfでconfig/initializers/wicked_pdf.rbを作成、内容を編集(wkhtmltopdfのバイナリ置き場を指定
exe_path: Gem.bin_path('wkhtmltopdf-binary', 'wkhtmltopdf')
日本語フォントのインストール
code:sh
yum install -y ipa-gothic-fonts
yum install -y ipa-mincho-fonts
viewの作成
いくつかヘルパーが異なるので専用のレイアウトから作る
views/layouts/application.pdf.erb
views/[TARGET]/xxx.pdf.erb
controllerの作成
code:rb
respond_to do |format|
format.html
format.pdf do
render(
pdf: 'file_name', # 必須
encoding: 'UTF-8', # 日本語化に必須
layout: 'application.pdf.erb' # 上で作成したもの
)
end
end
docxの作成
chrahunt/docx
Rails4でdocxを読み書き〜gem docx
あらかじめテンプレート用のdocxに、文章挿入ポイントとしてブックマークを仕込んだ物を作成しておく
code:rb
doc = Docx::Document.open('./tmp/テスト.docx')
doc.bookmarks'name'.insert_multiple_lines("九州男児", "日本一")
doc.bookmarks'value'.insert_text_after("9876")
doc.save('./tmp/test1.docx')
ただ、gem docxはテキストの挿入しかサポートしていないように思える
Pandoc
Pandocの比較的簡単なインストール方法 - Qiita
alphabetum/pandoc-ruby
sudo yum install pandoc
Controllerの応答パターン
respond_toとかcsvダウンロードとかあの辺
CSV出力
リクエスト時にformat: :csvとするか、URLの末尾に".csv"をつける事で、Viewを変更できる
通常(HTML)のViewが prize.html.haml だとすると、CSVのViewは prize.csv.ruby にできる。
特に何もしない場合
リクエストの拡張子(URLあるいはContent-Typeヘッダ)に対応したViewテンプレートを自動で選択する
xxx.html.erbやxxx.csv.ruby、xxx.json.jbuilderなんかを勝手に選んでレンダリングを行う。
この場合、ファイル名は自動的にアクション名になってしまうので、ファイル名を変えたい場合は一手間必要。
render :new を使う場合
本来xxx.html.erbのテンプレートを見に行く所を、new.html.erbを見に行くように矯正する
render format: content, status: :ok を使った応答
formatで指定したものとして応答する。
respond_to とは違い、リクエストを参照しないので、一意に決め打つ時に。
formatの部分はいろいろ選べる
plain: プレーンテキスト
json: JSON
redirect_to xxx_path を使う場合
本来xxx.html.erbのテンプレートを見に行く所を、302応答を返してxxx_pathへリダイレクトする
respond_to を使う場合
要求されたファイル拡張子に応じた処理の振り分けと、応答可能な拡張子のホワイトリストができる
code:rb
respond_to do |format|
format.html
format.csv do
send_data render_to_string, filename: "hoge.csv", type: :csv
end
end
これで、hoge.csvのダウンロードができる。(あとhtmlとcsv以外のフォーマットを受け付けない)
ファイル名を作っているのはsend_dataの仕業。
render_to_stringは、Viewの出力結果を文字列で受け取る,renderメソッドの代わりになるものなので、viewにhoge.csv.erb的なファイルが必要
prize.csv.rubyの内容はこんな感じ
code:rb
CSV.generate do |csv|
csv_column_names = "ギフト券送付", "メールアドレス"
csv << csv_column_names
@prizes.each do |prize|
csv_column_values = [
->{ "済み" if prize.prized }.call,
prize.user.email,
]
csv << csv_column_values
end
end.tosjis
ActiveSupport
Railsでタイトルを動的に
Railsでページごとにページタイトルを変える方法 - A Little Each Day
アップロードされたファイルの拡張子確認
raise I18n.t('import.not_csv') if file.content_type != Rack::Mime::MIME_TYPES['.csv']
リクエストURLから該当するControllerとActionを逆引き(アプリ内でRoutesを調査)
Rails.application.routes.recognize_path "users"
railsからHTMLタグの出力
HTML特殊文字のエスケープ - Ruby on Rails入門
文字列.html_safe
現在のDBの状態をschema.rbに書き込む
bundle exec rails db:schema:dump
マイグレーション使わずにテーブル作ったりした時に
coockieに値を暗号化して保存
cookies.signed[:user_id] = user.id
復号化
User.find_by(id: cookies.signed[:user_id])
sprocket(アセットパイプライン)のパス
アセットパイプライン | Rails ガイド
app/assetsは、カスタム画像ファイル、JavaScript、スタイルシートなど、アプリケーション自身が保有するアセットの置き場所です。
lib/assetsは、1つのアプリケーションの範疇に収まらないライブラリのコードや、複数のアプリケーションで共有されるライブラリのコードを置く場所です。
vendor/assetsは、JavaScriptプラグインやCSSフレームワークなど、外部の団体などによって所有されているアセットの置き場所です。
rakeタスクの作り方
RailsでRakeタスクの作成 - Qiita
rails g task task_sample でスケルトンを作る
code:rb
namespace :inactive_uesr do
desc "usage task"
task :task_name => :environment do
end
end
自作のrakeタスクから、他のrakeタスクを呼び出し
Railsでrakeタスクから別のタスクを呼び出す - 動かざることバグの如し
Rake::Task["sample:hoge"].invoke
Ruby on Railsでapplication.html.erbを適用したくないページの設定
Ruby on Railsでapplication.html.erbを適用したくないページの設定 - 木木木
適応しない
render :layout => nil
別のレイアウト
render :layout => "second_layout"
コントローラー全体にレイアウトファイルを適用したい場合
code:rb
class UserController < ApplicationController
layout "second_layout"
def home
...
end
def about
...
end
end
railsで定義している、MimeTypeの一覧
Rack::Mime::MIME_TYPES
テストでMimeType付きのFileオブジェクトが欲しいとき
code:rb
f = ActionDispatch::Http::UploadedFile.new({
filename: 'test',
type: Rack::Mime::MIME_TYPES'.csv',
tempfile: File.new('test/fixtures/files/employee.csv')
})
protect_from_forgeryを書く位置
こう書くとCSRFチェックで弾かれた
code:rb
class ApplicationController < ActionController::Base
default_form_builder ApplicationFormBuilder
before_action :set_paper_trail_whodunnit
before_action :sign_in_required
protect_from_forgery with: :exception
end
こう書く
code:rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
default_form_builder ApplicationFormBuilder
before_action :set_paper_trail_whodunnit
before_action :sign_in_required
end
binding.pryから脱出するコマンド
exit!
Railsのログをもう少しまともにする
Railsのログについて(Rails.logger) | 酒と涙とRubyとRailsと
受けたリクエストのURLを取得
request.original_url
railsでカスタムフォントを使う時
カスタムフォントはassets/fonts/配下に入れる(他の場所だと何かに定義しないと上手く動かない)
assets配下だとデプロイ後は置き場所が変わるので、font-url()を使用してパス指定する。
ただし、font-urlはコンパイルしないと機能しないので、CSSファイルに書いても動かない。
SCSSファイルにすること
I18nについて
どうも、ヘルパー扱いのようで、viewとcontrollerはt('hoge')で使える
Model周りではI18n.t('hoge')でつかえる。
tに入れるクエリは.区切りでパス指定できる。子持ちのパスの場合はハッシュで帰ってくる
ファイル名はコントローラ側で制御する
code:rb
respond_to do |format|
format.html
format.csv do
send_data render_to_string, filename: "ギフト券.csv", type: :csv
end
end
リクエストフォーマットの確認
request.format == :html
request.format == :csv
ルーティングヘルパーから、リクエストフォーマットの指定
prize_path(format: :csv)
言語設定の変更
code:application.rb
config.i18n.default_locale = :ja
をブロック内部に追加
デリゲート
早く知ってたら良かったrailsの技
このメソッドが呼ばれたらこのクラスに問い合わせてね、と指定する
code:rb
class Note < ActiveRecord::Base
belongs_to :user
delegate :name, to: :user
# => 最小構成、nameを呼ぶとuesr.nameが帰る。user == nilの場合は例外
delegate :name, to: :user, prefix: true, allow_nil: true
# => 基本構成、user_nameが使えて、user == nil の場合にnilが帰る
delegate :name, to: :user, prefix: :author, allow_nil: true
# => 応用構成、note.author_name が使えるようになる
end
基本の書式はこんな感じ
delegate [呼び出しメソッド], to: [移譲先]
prefixで、メソッドの接頭語を指定できる(プロパティ名が被ってる時などに)
allow_nilで、委譲先のオブジェクトが無い場合でもエラーにしない(nilを返す)
coffeeスクリプトを消すのに失敗
誤ってcoffiee-railsを入れっぱなしにしていた。
Gemfileから消してRailsを再起動すると、LoadError (cannot load such file -- coffee_script):とエラーが出るように
これはcoffee_scriptのキャッシュが残っているのが原因だったので、bin/rake tmp:cache:clearを実行することで解決
application.js, application.cssからnode_modulesへのrequire_tree
require_tree, require_directoryは、そのファイルからの相対パスになるので、3つくらい戻る必要がある
require_tree ../../../node_modules
でも、そもそもnode_modulesがデフォルトでルート扱いなので・・・
JavascriptからSprockets配下のアセットへのアクセス
ファイル名末尾に.erbをつける事で、<%= %>記法が使えるようになるので、
<%= image_tag("slickgrid/CheckboxY.png") %> なんかが使える
SCSSの場合はasset-pathやasset-path
Seed_fu
HTTP系の情報アクセサ
railsのメールテンプレートの確認用URL
http://localhost:3000/rails/mailers
seeds.rb 書き方
code:rb
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation:"foobar",
admin: true,
activated: true,
activated_at: Time.zone.now)
99.times do |n|
name = Faker::Name.name
email = "examle-#{n+1}@railstutorial.org"
password = "password"
User.create!(name: name, email: email,
password: password, password_confirmation: password,
activated: true,
activated_at: Time.zone.now)
end
Viewでプリントデバッグ(debugヘルパ)
debug(params) if Rails.env.development?
rails起動のふわっとした流れ
1. nginx起動する
2. unicorn起動する
3. Unixドメインソケットという概念でnginxとunicornが連携する
4. unicornがワーキングディレクトリからconfig.ruを探す
5. config.ruにRails起動のDSLが書かれているので、railsが起動
rubyのメソッド中において クラス名 と メソッド名 を取得する方法。
メソッドの中からクラス名とメソッド名を取得する
in-methodログなんかはp "#{self.class.name}##{__method__}"とか
ruby 例外情報からコールスタックの確認
e.backtrace
Concernの書き方
code:rb
module ConcernSmaple
extend ActiveSupport::Concern
included do
# wrire for scope
end
module ClassMethods
# write for Class methods
end
# write for instance methods
end
Railsでグラフとかを表示する
Railsプロジェクトでグラフ描画ライブラリChartkickを使用する手順
Viewから任意のタグ生成 3パターン
"<div></div>".html_safe
raw "<div></div>"
content_tag('div')
要求されたコントローラを取得
params[:controller]
要求されたアクションを取得
params[:action]
railsのproduction環境でpublic配下にアクセスできない
Ruby - Railsのproduction環境でpublic内の画像が表示されない(110661)|teratail
よく使うアセット関連の設定項目まとめ - Qiita
code:config/environments/production.rb
config.public_file_server.enabled = true
RailsデフォルトではENV['RAILS_SERVE_STATIC_FILES'].present?となっているので
環境変数定義してあげればOK
実環境ではS3とかに置きたいね
本番モードテスト
【Rails】本番モード準備
code:環境変数定義
RAILS_ENV=production
RAILS_SERVE_STATIC_FILES=1
SECRET_KEY_BASE=hogehogehogheo
code:プリコンパイル、DB準備
bundle exec rails assets:precompile
bundle exec rails db:setup
bundle exec rails db:migrate
code:起動
bundle exec rails s -e production
アセットのプリコンパイル試行錯誤
railsのProductionで手動でPrecompileし直す
precompileしたものを削除
bundle exec rake assets:clobber RAILS_ENV=production
precompileする
bundle exec rake assets:precompile RAILS_ENV=production
間違えてassetをプリコンパイルした時(プリコンパイルしたassetsを削除
rake assets:clobber
ちなみにプリコンパイルはこう
rake assets:precompile
Modelの世代管理
GitHub - paper-trail-gem/paper_trail: Track changes to your models' data. Good for auditing or versioning.
Railsで監査ログやバージョン管理機能を追加するPaperTrailの使い方をまとめてみた
変更履歴の一覧取得
code:変更履歴の一覧取得
<% @note.versions.sort{|a,b| b.index <=> a.index}.each do |version| %>
<% next if version.event != 'update' %>
<tr>
<td><%= version.index %></td>
<td><%= version.created_at %></td>
<td><%= User.find(version.whodunnit).name if version.whodunnit.present? %></td>
<td>
<%= form_with(model: version.reify, local: true) do |f| %>
<%= f.hidden_field :title %>
<%= f.hidden_field :body %>
<%= f.hidden_field :rollback, value: :true %>
<%= f.button '戻す', type: :submit, class: 'btn btn-primary' %>
<% end %>
</td>
</tr>
<% end %>
ApplicationControllerにbefore_action :set_paper_trail_whodunnitを入れておくこと
date_select型の内容解決
start_date(1i)なんかをDate型に変換
rails/attribute_assignment.rb at master · rails/rails · GitHub
code:rb
#
# combine date params from date_select helper
# for example
# {'start_date(1i)' => '2018', 'start_date(2i)' => 09, 'start_date(3i)' => 01}
# combine to
# {'start_date' => 2018-9-1]} # is TimeWithZone
# after, send to super
#
# see also https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment.rb
#
def initialize(attribute = nil)
return super if attribute == nil
# find date_select params
date_parts = {}
attribute.each do |k, v|
if k.include?('(')
date_partsk = attribute.delete(k)
end
end
# combine values
dates = {}
date_parts.each do |multi_key, value|
attribute_name = multi_key.split('(').first
datesattribute_name ||= {}
parameter_value = nil
if value.present?
# 'start_date(1i)' to "i"
value = multi_key =~ /\(0-9*(if)\)/ ? value.send('to_'+ $1) : value
# 'start_date(1i)' to "1"
position = multi_key.scan(/\((0-9*).*\)/).first.first.to_i
datesattribute_nameposition ||= value
end
end
# applying to params
dates.each do |name, values|
values = nil if values.all?(&:nil?)
type = name.split('_').last
if %w(date month).include?(type)
if values.size != 3
values = nil
else
values = "%s-%s-%s" % [values1, values2, values3]
values = values.in_time_zone
end
end
attributename = values
end
super
end
ふわっとした理解
'('で引っ掛けて、date_selectによるものかどうかを判定
date_select由来のデータなら退避してparamsから削除
退避した各paramに対して、'('以前を取り出して属性名とする
この属性名に対応する箱を用意
param_keyに'(0-9i)'があれば to_i を呼ぶ
param_keyに'(0-9f)'があれば to_f を呼ぶ
入力にも和名を使いたい
実データコードで持つ意味無いのでは案件
入力パート
バリデーション直前に入力された値とエイリアスマップとを突合して、コード値に置き換え
出力パート
エイリアスマップを舐めて、変換メソッドを製造する
code:rb
class BusinessClassification < ApplicationRecord
# エイリアスマップ
ALIASES = {
sbr_account_classification_code: {
'無形' => '01', '雑費' => '02'
},
sales_classification: {
'企画' => '01', '開発' => '02', '保守' => '03'
}
}.freeze
# 出力用メソッド生成
# define name getter
# ex.
# generate 'sbr_account_classification_code_name' method
ALIASES.each do |target, pairs|
define_method "#{target}_name" do
ALIASEStarget.key(self.send(target))
end
end
# 入力時に名称:コード変換
before_validation :apply_aliases
private
def apply_aliases
ALIASES.each do |target, pairs|
input = self.send(target)
if pairs.keys.include?(input)
# find alias
selftarget = pairsinput
end
end
end
end
CSRF
## SameSite
HTTP クッキーをより安全にする SameSite 属性について (Same-site Cookies) | ラボラジアン(https://laboradian.com/same-site-cookies/)
[Railsでセキュリティ用ヘッダをまとめて付与secureheadersGem](https://morizyun.github.io/ruby/library-secureheaders.html)
## RestAPIの雛形(スケルトン)作成
GitHub - bploetz/versionist: A plugin for versioning Rails based RESTful APIs.(https://github.com/bploetz/versionist)
## vendor配下にbundle install
bundle install --path vendor/bundler
## Railsでファイルアップロード
ActiveStorageの話
File Upload 2017 - Speaker Deck(https://speakerdeck.com/willnet/file-upload-2017)
## ElasticSearchのインストール
elasticsearch+kibanaをCentOS7にインストールしてみた - web-technical-blog(http://web-technical.hatenablog.com/entry/2017/12/22/110939)
## scaffoldの生成ファイルカスタマイズ
`rb
Rails.application.config.generators do |g|
g.scaffold_stylesheet = false # ignore generate scaffold.scss
g.test_framework = false # ignore generate tests
g.jbuilder = false # ignore generate jbuilders
g.assets = false # ignore generate javascript and stylesheet
# g.stylesheets = false # ignore generate stylesheets
# g.javascript = false # ignore generate javascript
g.helper = false # ignore generate helpers
g.integration_tool = false # ignore unit_tests
g.system_tests = false # ignore system_tests
g.active_record = {
migration: false # ignore migration
}
end
`
## bootstrapとjquery-uiの競合
Bootstrap3のtooltipが動かないと思ったら、jQuery UIのtooltipと競合していた件(http://right69.net/tootip-kinoushinai/)
メソッド名が同じ・・・
後がちになるので読み込み順を操作する。
## RailsでWebAPI式のアプリを作る雛形
RailsでAPIを作成するために色々比較したので所感と実装方法のご紹介(https://qiita.com/Kaki_Shoichi/items/d4adcf0298ed0b4614a2)
## Railsで簡易なあいまい検索
User.where('name LIKE ?', "%#{params[:word]}%")
## Ruby / Railsでrequireで使用するパスの指定方法と拡張方法
RubyのrequireとActive Supportの自動requireについて(https://morizyun.github.io/blog/ruby-require-active_support-load/index.html)
rubyの場合、ローカルファイルへのrequireは require './hoge'と書く
ActiveSupoort影響下では、フォルダパスを指定して自動でrequireしてくれる
`rb
require 'active_support/dependencies'
ActiveSupport::Dependencies.autoload_paths << "/path/to/my_library"
`
## erbで範囲コメント
どうにもうまい方法がない模様
.erbのコメントアウト - anmitsuchan’s blog(http://anmitsu.hatenadiary.com/entry/2015/01/14/140544)
`rb
<% if false %>
hogehoge
<% end %>
`
## Stimulus
Railsの親玉(Basecamp)が作成したjsライブラリ。
Railsと親和性が高くて、特にTurbolinks影響下でもちゃんと動いてくれる
立ち位置としてはVue.jsやReactなどと同じポジション
Stimulus Handbookを大体やったので所感を書く - patorashのブログ(https://patorash.hatenablog.com/entry/2018/03/06/015047)
## RailsでDatatablesを真っ当に使う
Manual(https://datatables.net/manual/)
DataTables事始め - Qiita(https://qiita.com/taka4sato/items/277e2218684562affda7)
#340 DataTables - RailsCasts(http://railscasts.com/episodes/340-datatables)
- tbody内部はカラにしておく
- 画面表示用のパスとは別に、json受送信用のパスを切っておく(今回は拡張子切り替えで対応)
- DataTablesのイニシャライザに色々オプションをつける
- serverSide: true
- フィルタ、ページング、ソートの計算をサーバーで行う
- ajax: url
- データ取得元のパスを書く
- 応答クエリのフォーマットは以下を参照、デフォルトだとdataプロパティパターンの模様
Ajax(https://datatables.net/manual/ajax)
- DataTablesがクエリを投げる際に、自前の検索条件も合わせて投げるよう修正
- クエリの追加を行う
DataTables example - Custom HTTP variables(https://datatables.net/examples/server_side/custom_vars.html)
- HTML向けには検索せずに応答を返す、JSON向けには検索を実施
- DataTables由来の検索パラメータ処理を書く
- やる事が多すぎるのでGemを投入
jbox-web/ajax-datatables-rails(https://github.com/jbox-web/ajax-datatables-rails)
- DataTable側をこのgemに合わせるように修正(下記)
- view_columnsメソッドは、各カラムのメタデータを定義する。基本的にはクライアントJSに渡したcolumnsと同じものを定義
- sourceに書いた情報は検索やオーダーに使うSQL文に反映される
- 固定値としたい場合は、sourceにnilを入れて、orderableをfalse、searchableをfalse
- dataメソッドは、取ってきたレコードと応答JSONの対応関係を記述する
- 固定値を入れるのはここ
- get_raw_recordsに実際の検索処理を記述する
独自形式の検索条件が使いたい場合はjbox-web/ajax-datatables-rails(https://github.com/jbox-web/ajax-datatables-rails#pass-options-to-the-datatable-class)を参照
ajax-datatables-rails向けのDatatable初期化処理例
`js
// users.js
jQuery(document).ready(function() {
$('#users-datatable').dataTable({
"processing": true,
"serverSide": true,
"ajax": $('#users-datatable').data('source'),
"pagingType": "full_numbers",
"columns": [
{"data": "id"},
{"data": "first_name"},
{"data": "last_name"},
{"data": "email"},
{"data": "bio"}
]
// pagingType is optional, if you want full pagination controls.
// Check dataTables documentation to learn more about
// available options.
});
});
`
## redirect_toのバリエーション
redirect_to の引数とかのメモ - Qiita(https://qiita.com/kanpe777/items/c5154b58c852855deefc)
## Railsでファビコン
favicon設定 Rails - Qiita(https://qiita.com/ntkgcj/items/6643a07a43a36029dc9b)
## RailsのModelでコールバックメソッドの追加をする
Ruby on Rails ガイド - 体系的に Rails を学ぼう(https://railsguides.jp/active_model_basics.html#callbacks%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)
define_model_callbacks :xxx でコールバックのフック名を定義する
(before_xxx みたいなメソッドが使えるようになる)
コールバックを叩くときは、
`rb
run_callbacks(:xxx) do
# doing
end
`
メソッドを呼び出すと、ブロック前後でコールバックメソッドがキックされるようになる
## Railsでflashメッセージ
僕の中でRailsのflashの使い方が落ち着いてきた - Qiita(https://qiita.com/youcune/items/12b153c08db695952e47)
some_controller.rb
`rb
flash:success = 'success!'
flash:info = 'info'
flash:warning = 'warning'
flash:danger = 'danger'
`
some_view.html.haml
`rb
- flash.each do |type, msg|
%div{class: "alert alert-#{type}"}= msg
`