nginxのmoduleを追加する
nginxにはmoduleという概念があります。
これは、各機能がmodule単位で実装されており、moduleを組み合わせた構成になっています。
moduleには「静的module」と「動的module」の二種類があります。
「静的module」はビルドした時にしか組み込みができません。
「動的module」はビルドし直すことなく、追加することができます。
この概念自体はApacheからあります。
そして、nginxは昔は「動的module」をサポートしていませんでした。
https://heartbeats.jp/hbblog/2016/02/nginx-dynamic-modules.html
1.9.11
で対応したようです。
ただし、一部だけになります。
下記は動的に組み込みができるものです。
Certified Dynamic Modules - NGINX
moduleは、上記以外には、サードパーティー製のものがあります(OSSに感謝)
https://www.nginx.com/resources/wiki/modules/
動的に組み込めれるものもあれば、静的に組み込むしかないものもあります。
ということは、きちんと最初で使用するであろうものは、用意しておくほうがいいですね。
ソースコードからビルドする
僕はmoduleを追加するためにソースコードからビルドしています。
ソースコードのダウンロードからやります。
deployer@ik1-324-22232:wget http://nginx.org/download/nginx-1.13.5.tar.gz deployer@ik1-324-22232:tar xvf nginx-1.13.5.tar.gz deployer@ik1-324-22232:cd nginx-1.13.5
まずは現状確認
deployer@ik1-324-22232:~$ sudo nginx -V nginx version: nginx/1.13.5 built by gcc 6.3.0 20170516 (Debian 6.3.0-18)
何も入っていません。
なんでこうなっているのかというと、自分はModuleを簡単に追加できると思っていたからです。
ここからhttpsを使おうとすると、nginx_http_ssl_module
がほしいです。
最初から入れておけばよかった。
ということで追加します。
ついでにwith-http_stub_status_module
も追加します。
deployer@ik1-324-22232:/tmp/nginx-1.13.5$ sudo ./configure --with-http_ssl_module --with-http_stub_status_module --prefix=/usr/local/nginx --sbin- path=/usr/sbin/nginx deployer@ik1-324-22232:make deployer@ik1-324-22232:make install
これでパッケージをもう一度ビルドできました。
deployer@ik1-324-22232:/tmp/nginx-1.13.5$ sudo nginx -V nginx version: nginx/1.13.5 built by gcc 6.3.0 20170516 (Debian 6.3.0-18) built with OpenSSL 1.1.0f 25 May 2017 TLS SNI support enabled configure arguments: --with-http_ssl_module --with-http_stub_status_module --prefix=/usr/local/nginx --sbin-path=/usr/sbin/nginx
結論
原則動的に追加できないなど、nginxの特徴を押さえておくべきだった・・・orz
debianでmysqlの最新版をインストールする
何も考えずにapt-get install mysql-server
とすると、5.5系になります。
パッケージを更新しないといけません。
https://dev.mysql.com/downloads/repo/apt/
ここに書いてある場所からダウンロードして、更新します。
#wget https://dev.mysql.com/get/mysql-apt-config_0.8.7-1_all.deb #dpkg -i mysql-apt-config_0.8.7-1_all.deb←更新する
あとはいつも通りです。
#apt-get update #apt-get install mysql-server
参考
管理画面に他人の人がアクセスされてきた場合の対処方法
何も考えずにリダイレクトをしていました。
リダイレクトが悪い理由
リダイレクトをするということは、ページがあるということがバレます。
ページがないのなら、404を返すのがベターです。
ということは、404ページを作成して、それを返すのがいいです。
今は404ページを作成していないので、雑な返し方。
class Admin::ApplicationController < ApplicationController before_action :authenticate_admin! layout 'admin' private def authenticate_admin! head :not_found unless admin_signed_in? end end
これを継承すれば、Adminに関しては、基本的にログインしていないと404になります。
ちょっとしたことですが、疑問に思いました。
皆さんはどうしているのでしょうか。
webpackerを使用した時にcssをどこに置くのかについて
webpackerを使用していて、cssをどうするか悩みました。
いや、そもそも何に悩んでいるの?という話だと思います。
jsファイルは原則javascript/packs
に存在する→jsから読み込むcssファイルはどこに置く?→javascript/styles
を作成して、そこから使用するようにする→全部そこに置いたほうがよくない?
一番最後の全部javascript/styles
に置くというのは、webpackに全てを預けるということになります。
mastodon
は全てをjavascript
に含んでいます。
https://github.com/tootsuite/mastodon/tree/master/app/javascript
メリット
- ファイルの置く場所が固定できる→書くときに迷わない
- 完全にsprocketsの呪縛を解くことができる(cssも)
- ビルドを完全に一元化できる(webpackのみ)
デメリット
- webpackが廃れた時の移行コストが高い。
- imagesも置かないと、中途半端になる。
解決策
- webpackとともにする
- css/imagesは
sprockets
を利用する
ここで後者を選びました。
理由
- railsの資産が残る
image_tag asset_pack_path('logo_full.svg')
と書かなくて良い(imageがpackってのはちょっと変な気がする)
- 将来的な移行コスト(webpackはおそらく廃れるはず)
ただし、jsしか使用しない、cssはjavascript/styles
を作成して、そこから使用するようにします。
こうすると、jsしかクラスはjs-xxx
として利用すれば、ネームスペースでぶつかることはなくなると思います。
想定されること
Q node_modules配下のcssはどうする?
A sprocketsに任せます
@import 'swiper/dist/css/swiper'
これはswiperというnpmのcssですが、sprocketsから読み込みをしています。
asstes
のpathを確認します。
Rails.application.assets.paths => "/Users/xxx/rails/xxx/node_modules"
これで入っていないようでしたら、追加しましょう。
# config/application.rb config.assets.paths << config.root.join("node_modules")
Q sprocketsのsassの変数共有したい
A webpackerの設定でなんとかできるはず(これは調べる)
結論
ルールを決めることが大事ですね。
railsでboolean値のvalidationをする方法
ちょっと罠にかかりました。
validates :publish, presence: true
いつも通りpresence: true
を書いていました。
こうすると、errorになります。
なぜ、そんなことが起こるかです。
rails/presence.rb at d57356bd5ad0d64ed3fb530d722f32107ea60cdf · rails/rails · GitHub
def validates_presence_of(*attr_names) validates_with PresenceValidator, _merge_attributes(attr_names) end
class PresenceValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) record.errors[attribute] << "Local validator#{options[:custom]}" if value.blank? end end
value.blank?
になっていますね。
[1] pry(main)> false.blank? => true [2] pry(main)> true.blank? => false
この結果、falseの場合に反応しています。
なので、別のvalidationを使います。
validates :publish, inclusion: { in: [true, false] }
これでtrue or falseが存在する場合に反応するようになります。
意外なところで存在を知った。
SQLでクロス集計をしてみる
SQLって表も簡単に作成できるんだなって最近感動しております。
今回やろうとしていることは、クロス集計です。
年 | 春 | 夏 | 秋 | 冬 |
---|---|---|---|---|
2000 | 10 | 10 | 8 | 9 |
2001 | 9 | 10 | 8 | 9 |
2002 | 10 | 10 | 8 | 10 |
年毎の作品を集計したいとかありそうじゃないですか。
ということで、やってみました。
テーブルの構成
mysql> show columns from works; +------------------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | title | varchar(255) | NO | | NULL | | | season_year | int(11) | NO | | NULL | | | season | int(11) | NO | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------------------+--------------+------+-----+---------+----------------+
season_yaerに2017
seasonに「0 = 春」「1 = 夏」「2 = 秋」「3 = 冬」
こういうデータが入っています。
SQL文
春夏秋冬をどうするかということになります。
ここでcase文を使用します。
select season_year as 年, count(case when season = 0 then 1 else null end) as 春, count(case when season = 1 then 1 else null end) as 夏, count(case when season = 2 then 1 else null end) as 秋, count(case when season = 3 then 1 else null end) as 冬 from works group by season_year;
count(case when season = 0 then 1 else null end) as 春,←ここが大事。
case文であればcountして、なければcountしないnullを入れます。
+------+-----+-----+-----+-----+ | 年 | 春 | 夏 | 秋 | 冬 | +------+-----+-----+-----+-----+ | 2000 | 17 | 15 | 12 | 16 | | 2001 | 10 | 8 | 10 | 10 | | 2002 | 12 | 16 | 10 | 11 | | 2003 | 15 | 18 | 10 | 16 | | 2004 | 21 | 15 | 15 | 14 | | 2005 | 12 | 20 | 17 | 11 | | 2006 | 19 | 18 | 14 | 15 | | 2007 | 15 | 18 | 19 | 13 | | 2008 | 16 | 18 | 27 | 20 | | 2009 | 28 | 23 | 26 | 26 | +------+-----+-----+-----+-----+
結果はこんな感じになります。
ここからさらに発展させます。
全体・前期・後期で知りたいんだってパターンですね。
select season_year as 年, count(case when season = 0 then 1 else null end) as 春, count(case when season = 1 then 1 else null end) as 夏, count(case when season = 2 then 1 else null end) as 秋, count(case when season = 3 then 1 else null end) as 冬, count(season) as 全体, count(case when season in(0, 1) then 1 else null end) as 前期, count(case when season in(2, 3) then 1 else null end) as 後期 from works group by season_year;
in
で条件分岐してあげます。
+------+-----+-----+-----+-----+--------+--------+--------+ | 年 | 春 | 夏 | 秋 | 冬 | 全体 | 前期 | 後期 | +------+-----+-----+-----+-----+--------+--------+--------+ | 2000 | 17 | 15 | 12 | 16 | 60 | 32 | 28 | | 2001 | 10 | 8 | 10 | 10 | 38 | 18 | 20 | | 2002 | 12 | 16 | 10 | 11 | 49 | 28 | 21 | | 2003 | 15 | 18 | 10 | 16 | 59 | 33 | 26 | | 2004 | 21 | 15 | 15 | 14 | 65 | 36 | 29 | | 2005 | 12 | 20 | 17 | 11 | 60 | 32 | 28 | | 2006 | 19 | 18 | 14 | 15 | 66 | 37 | 29 | | 2007 | 15 | 18 | 19 | 13 | 65 | 33 | 32 | | 2008 | 16 | 18 | 27 | 20 | 81 | 34 | 47 | | 2009 | 28 | 23 | 26 | 26 | 103 | 51 | 52 | +------+-----+-----+-----+-----+--------+--------+--------+
以上です。
case文がこんな使い方あるとはなーって感じです。
Deviseでユーザー登録後のリダイレクト先を変更する
Deviseのカスタマイズに少し苦労しました。
大体標準通りに使えば問題ないのかもしれませんが、少し加工しようとするとちょっと調べないといけないですね。
今回行うことは、Deviseでユーザー登録後に、Thanksページに飛ばすことです。
リダイレクト自体は割と簡単なのですが、コントローラーにアクションを追加するのに手間取りましたorz
コントローラーをカスタマイズする
今回のDeviseはユーザーモデルをベースとして考えています。
まずはカスタマイズするために、下記のコマンドを打ち込みます。
rails generate devise:controllers Users
これでテンプレートが作成されるかと思います。
変更するコントローラーはclass Users::RegistrationsController < Devise::RegistrationsController
になります。
thanksアクションを入れます。
class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] # GET /resource/sign_up # def new # super # end # POST /resource def create super end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end def thanks end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end end
routesを設定する
ここが少し戸惑いました。
devise_for :users, controllers: { registrations: 'users/registrations' }
上記を追加して、registrationsの動作をusers/registartions
に設定します。
次に、アクションをthanksページのroutesを追加します。
devise_scope :user do get 'users/thanks' => 'users/registrations#thanks' end
devise_scope
で設定しないと、request.env[“devise.mapping”]でroutesの設定がされません。
def devise_scope(scope) constraint = lambda do |request| request.env["devise.mapping"] = Devise.mappings[scope] true end constraints(constraint) do yield end end
こんな常識知らないよって感じですが、設定しましょう。
ユーザー登録後のリダイレクト先を変更する
def after_inactive_sign_up_path_for(resource) users_thanks_path end
users/registaration
でコメントアウトされていると思います。
ここに追加すれば終わりです。
まとめ
ドキュメントとソースコードを見よう。
find_by_カラム名のメソッドが動的に生成されていたという事実
例えば、Fooモデルにtitleというカラムがあるとする。
Foo.find_by(titile: "foo") Foo.find_by_title("foo")
下でも検索できる。
いつも上ばっかり使っていたので、下のパターンがあるとは知らなかった。
補足
rubocop的には上の方がいい。
Class: RuboCop::Cop::Rails::DynamicFindBy — Documentation for rubocop (0.49.1)
rails-syle-guide的に非推奨なので。
ttyとptsについて
dokcer runのオプションで意味不明だったので、調べていました。
docker run -it ←こいつ
% docker run --help -i, --interactive Keep STDIN open even if not attached -t, --tty Allocate a pseudo-TTY
ここでTTYが出てきました。
TTYとは
ttyとは、標準入出力となっている端末デバイス(制御端末、controlling terminal)の名前を表示するUnix系のコマンドである。 元来ttyとはteletypewriter(テレタイプライター)のことを指す。
ターミナルで打つとこうなります。
% tty /dev/ttys004
実際にターミナルで打っている端末の情報ですね。
よくある遊びです。
ここでターミナルを別のウィンドウで立ち上げます。
% tty ←ターミナル1 /dev/ttys004 % tty ←ターミナル2 /dev/ttys006 ターミナル1のウィンドウから下記コマンドを実行する % echo "Hello tty" > /dev/ttys006 % Hello tty←ターミナル2
これを実験するとどういうものかわかりやすいと思います。
pts
ptsはsshでログインした時の端末の情報です。
tty /dev/pts/0
ということは、誰かがsshで同時接続していた場合に、相手をびっくりさせることができますね。
【参考】
ローカル環境のURLをlocalhost以外にする方法
localhost
ってださいなって思う時があるじゃないですか?
そんな時に名前をhostを変える方法です。
/etc/hosts
があると思います。
この設定ファイルに付け足します。
127.0.0.1 foo.com
これでrails s
するとhttp:foo.com:3000
でアクセスできます。
:3000
がいるのはポートの関係ですね。
こうすると、「こいつわかってるやつじゃね?」って感じられそう。
以上です。