Railsで、投稿前の確認画面で画像をプレビューするための戦い
結論
- tmp配下に置かれているファイルをpublic配下に一時保存して、それを使ってなんとかする
情報
ファイルの保存先: "#{Rails.root}/public"
書き込みはこうする:
file = File.open("#{Rails.root}/public/#{file_name}") file.write(読み込んだバイナリファイル) file.close
file.close
は使ったら片付けよう的なやつです。
ActionDispatchに飲み込まれているtmpファイルをpublicに再配置するならこんな感じ
なお、 params[:image]
に画像がアップロードされているものとする。
file = File.open("#{Rails.root}/public/#{params[:image].original_filename}", "w+b") file.write(params[:image].tempfile.read) file.close
なお、JSONを受け付けてJSONをレスポンスするようなAPIにデプロイする場合、これらのデータをbase64形式で投げるのが最も妥当と考えられる。
multipart: true
は妥当な選択肢のように見えるけれど、データの受け口が決まっている場合に画像を含む場合だけそれに対応させるのは結構大変な気がする。
そのうち追加でまとめたいところ。。
【Android】apkをインストールしたらメイン画面(アプリ一覧)にアプリが表示されないときのAndroidManifest.xmlの書き方
Railsおじさんでしたが、Androidとの殴り合いが増えてきまして、泣きながら戦っていて、インターネットにあまりにも情報が足りないと思ったので筆をとりました。
この記事の対象読者
- apkをインストールしたらメイン画面(アプリ一覧)にアプリが表示されない人(タイトルそのまま)
ここに書いてあるんですけど、 そしてここに書いてあることばっかり検索に出てくるんですけど、 やってんだよこっちは!!って思ったときにドツボにハマったので、 同じ悩みを抱える人が今後二度と現れて欲しくないので書いています。
Androidアプリがメイン画面に表示される条件
余計なのもついてるかもしれないけど、100%動いてほしいので確信がないやつも書いています。 なくてもいいだろ、関係ないだろ、というのは外しています。 かなり最低限の構成にすると以下のような感じ。
com.hogeapp.fuga
とか @mipmap/ic_launcher
とか @string/app_name
とかはよしなにしてください。不安な人は名前まで合わせちゃうと確実に動くと思います。
name, label, Activityの指定、intent-filterにあの二つの記載をすること、が重要みたいです。
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hogeapp.fuga" android:versionCode="1" android:versionName="1.0"> <application android:name=".MainApplication" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
今回詰むに至った原因
差し障りなさそうな範囲で書くと、ReactNativeで動けばええやろということで以下のような感じに書いてたんですけど、
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hogeapp.fuga" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <application android:name=".MainApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:label="@string/app_name" android:screenOrientation="portrait" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="main" android:scheme="hogeapp" /> </intent-filter> </activity> (中略) </application> </manifest>
これは詰みます。 次のように、必ずintent-filterを分けて書くことが肝要です。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hogeapp.fuga" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <application android:name=".MainApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:label="@string/app_name" android:screenOrientation="portrait" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!-- ここと --> <intent-filter> <!-- ここね --> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="main" android:scheme="hogeapp" /> </intent-filter> </activity> (中略) </application> </manifest>
これに気づけなくて「情報全部揃ってるだろ!」って6時間ぐらいインターネットをさまよいました。かなしい。
というわけで、皆さんも気をつけてください。よろしくお願いします。
Railsでメール送信システムを作るために、SMTPとかSESとかDKIMの関係の整理を試みる
昔はうまくやれてたのに、別件で雑にこなそうとしたら動かなくなってしまったので悲しい気持ちでまとめていく。
きちんとやろうとすると本当にめんどくさいのでもっと世界がいい感じになってほしい。
細かい書き方やスクショなどはおいおい追記するかもしないかも、ということで、初回公開時点ではとりあえず概念だけ整理していく。
この記事はまだ修正中だけどちょう最低限の記述ができたので公開されています。
この記事の対象読者
- Railsサクッとメール送信機能作りたいんだけどいろんな情報の関係性がよくわからない
- メール送信機能つくったのに届かないとか言われたりする
- メールの送信元が本来想定しているメールアドレスと違うのなんでなん
この記事の対象じゃない読者
後で書くかもしれないけど、メールを受信したい場合にはやることが全く異なるので
- メールをサーバーで受信して転送したりうまいことやりたい人
は対象になりません。
メール送信できるようにするまでの基本的な流れ
たぶんこうだと思う。
- 送信元になるメールアドレスのドメインを取得しておく
- メール送信をするメールサーバーを用意する
- 送信するメールアドレスを指定し、そのメールアドレスがブラックリスト化されないようにDKIM及びSPFの設定をする
- メールサーバーに対してSMTPまたはHTTPの形式で通信し、送信リクエストを行う
分解していくと、関連するサービスなどの立場がわかりやすい。
送信元になるメールアドレスのドメインを取得しておく
ここでは、お名前.com、ゴンベエドメインなどのドメイン取得サービスでドメイン取得が必要になる。
基本的にドメイン取得後は、デフォルトではドメイン取得サービスが提供しているDNSがドメインの取り扱いを管理しているので、
ドメイン移管などの処理をしていない場合には、ドメインに関する設定はそのサービス内で行うことになる。
メール送信をするメールサーバーを用意する
メール送信を行うにはメールサーバーが必要で、ここの設定がわからないと結構苦労することが多い。
テスト送信と実際の送信で使うサービスが異なるケースが多い。
よくやるのは、テストではgmailを使うパターン。
また、最近聞いたので割とよさそうだなと思ったのは、MailTrapというので実際にメール送信はせずに、どんなメールが送信される処理がされたか、まで確認するパターン。
mailtrap.io
実運用においては、Amazon SESやSendGridというサービスを使って、メール送信を肩代わりしてもらうものになる。
なお、よそのツールは使わないんじゃ! 自分でサーバー構築するんじゃ! という場合に出てくる単語はSendMailやPostfixなどがある。
一度知識がなさすぎた頃に検索するたびに出てきてこいつが主流なのかと勘違いしてやってみたことがあるが、ドキュメントが古いものばかりな上に、バウンスの管理などがろくにできず結局ほとんど届かなかったり、yahoo.co.jpに特別な設定が必要で届かないってbizの人に怒られたり、TLSの設定とかがわけわかなくなって地獄を見るのでメールの専門家になりたい人以外にはおすすめしない。
- Amazon SES
割と有名なサービス。後述するDKIMやSPFの設定とかデフォルトでいい感じに埋めてくれたりするのでかなり便利。
ドメインの所有権を持っていないと、メールアドレスの認証ができなくて送信できないので、事前にドメイン取得を済ませておき、ドメイン管理者としてメールを受け取れるようにすることが必要。
本番運用に切り替えるには、送信制限の解除などをフォームから申請する必要があるのでググってやっていくこと。
なお、日本のキャリアメール(ezweb.ne.jpとかdocomo.ne.jpとか)に届かないケースがあるらしく、公式でもそういうアドレスに送りたいならやめとけ、みたいなことが書いてある。
- SendGrid
これまた有名なサービス。
事前に審査が必要なため、ドメインの所有権を持っていなかったり、サイトのURLが用意できてなかったり、真面目に使う気がなさそうだと審査に落ちる。
ちゃんと運用する気なら基本的には審査通るのと、無料枠が十分にあること、メールが届かないといった文句を全然言われないで済むことから、かなりおすすめのサービス。
送信するメールアドレスを指定し、そのメールアドレスがブラックリスト化されないようにDKIM及びSPFの設定をする
一番わけわかんなくてキレる人が最も多く発生する(当社調べ)手順。
一介のプログラム書いてるエンジニアが普段絶対関わることのない領域であり、かつ概念が謎な上に設定方法も謎なので切なくなることが多い。
湯河原にあるおんやど恵で開発合宿に行ってきたメモ
約2年ぶりの投稿です。お元気でしたか。
役員をやっていた会社を辞めたりフリーランスになったり会社を作ったりしました。
2記事しかないブログにもかかわらず定期的にはてブがついているようで、2年前と比べてより正確な情報を発信すべきなんじゃねえの・・・って思ったりしています。
今回は(株)ジシバリで開発合宿に行ってきたので、そのことを軽くブログにまとめたいと思います。
開発合宿の場所
言わずと知れた開発合宿御用達のおんやど恵さん。
開発合宿プランの優遇などもさることながら、湯河原という素敵ロケーションもあり非常に素敵な旅館です。
個人的には2どめ、会社では初めての参加です。
開発合宿プランはこちらです。
24時間使える会議室、全館でしっかり繋がるWi-Fi、最強足湯開発という連係プレイで、バスと歩きを組み合わせれば2~3時間で海まで行ってご飯食べて帰ってこれたりするのですっげえいいです。
ご飯も季節ものをしっかり用意してくれていておなかいっぱい食べれます。段階的にめっちゃ出てくるので油断してはいけません。
何をやったか
各自好きなものを作ったり過去の罪を清算したりしていました。
- ReactNativeを使った案件の詰め
- fastlane使ってデプロイするように頑張ったりしてました。fastlaneとfabric、安全に使えるようになるまでが結構闇深い
とか、ギークっぽいことも受託会社っぽいこともしていました。
2日目の夜には創業半年ということでこれまでの実績と決まっている仕事を振り返ったりして、結構頑張ったねえおれたち、みたいな話をしたりしてます。
おまけ
採用拡大とか全然していないんですけど、楽しく働ける会社なので興味のある人は元代々木町まで遊びにきましょう。
あと開発合宿したい人は初回はとにかくおんやど恵さんに行くことをオススメします。良いです。
なんかこう、安心感がある。素敵です。
さて、というわけで、引き続きやっていきましょう。
DNSとかネームサーバとかRoute53とかAレコードとかCNAMEとかがわからない人のためのまとめ
表題の通り。
いくら調べてもわかるようにまとめてる人がいなくてさすがにムカついたのでまとめた。
この記事の対象読者
- 「ドメインの設定わかりづらすぎるよお死ぬう」
- 「DNSサーバとかネームサーバってなんなのマジで・・・」
- 「AレコードとかCNAMEとかよくわからないしよくわからない理由で設定が拒否された」
- 「よくわかってないのに動いちゃったしヤバイ気がしてるしこわい」
- 「Route53に移管っていう単語が死ぬほど出てくるけどそもそもなんなのこれ」
webサーバを公開してから、取得したドメインでそのサーバにアクセスできるようにするまでの流れ
さて、まずは全体の大まかな流れを見てみよう。
- webサーバでwebサイトを公開する
- webサーバのIPアドレスを確認する
- ドメインを取得する
- ドメインを取得したサービスで、使用するDNSサーバ(ネームサーバ)を設定する
- DNSサーバでドメインとIPアドレスを紐づける設定をする
- 設定が反映されるのを待つ
- できた!
たったこれだけなんだけど、DNSサーバってなんなんだとか、紐付けってどうするんだ、ってなって仕組みがどんどんわけわからなくなるので整理する。
あと、ネームサーバって単語があちこちで出てくるわりにどこにあるかわかりづらくてAWSなんかが独自サービス出したりしたせいで余計わかりづらくなってる気がするのでそのあたりも含めて整理したい。
IPアドレスとドメイン名について
とりあえずこれだけは理解してないと先の話がわからなくなるので整理。
IPアドレス
webを通じて何かを見るためには、その見たいものが置いてある場所をPCに対して指定する必要がある。
荷物を送るには住所がわからないといけない、みたいな話。
その住所のことをIPアドレスという。
IPアドレスの具体例
一番下の数字の羅列をURLバーに入れるとgoogleのページが表示されるはず(2015年9月14日現在)。
これは、この数字がgoogleのサイトの住所を表しているからなのだ。
ドメイン名
でもgoogleだったらふつうgoogle.comでサイトにアクセスする。
このときに使うものがドメイン名と呼ばれている。
これは数字だと使う人がわかりづらいから文字でIPアドレスを伝えましょうということ。
なぜドメイン名を使うのか
国立競技場に行きたい人は「今から東京都新宿区霞ヶ丘町10番2号に行くんだー」と言わない、みたいな話。どう考えても「今から国立競技場行くんだー」の方が伝わるしわかりやすい。
それと同じで、173.194.117.128よりgoogle.comの方がわかりやすいので、ドメイン名というものを使う。
DNSって何?
DNSはドメインネームシステムというもので、住所と場所の名前をつなぐ対照表みたいな感じ。
みたいな感じで、それぞれをちゃんと一致させてくれるもの。
こんな表があれば、国立競技場に行きたい、と言ったときに具体的な住所がわかるので、たどり着くことができる。
現実世界では地図などがそれにあたるわけだけど、webにおいては、DNSというものを使って台帳管理をしているわけだ。
DNSサーバまたはドメインネームサーバについて
さて、こうやって住所と名前をつなぐ台帳があるわけだが、どこに台帳を見に行くか、という問題がある(世界中の情報を手元に置いておくわけにもいかないので)。
インターネットがない頃は、地図屋に地図を買いに行ったり、役所に戸籍謄本をあげに行ったりしてたけど、それに近い。
で、これらの台帳はDNSサーバというところで管理されている。ドメインネームサーバとかネームサーバとか呼ばれたりもする。
DNSサーバ自体も、それぞれの住所を持っている。まさに役所みたいな感じ。
ドメインを取ったときのネームサーバ設定云々というのは、この「住所を確かめるための役所を指定する」というのに近い。
例えばお名前ドットコムでドメインを取った場合のネームサーバ
例えばお名前ドットコムでドメインを取った場合、管理画面のネームサーバの変更、というところからネームサーバを指定できる。
ネームサーバは、お名前ドットコムなどのドメイン取得サービスがそのまま用意していたりするし、AWSを使う人にはAmazonが
Amazon Route 53(ドメインネームサーバー – DNS サービス) | アマゾン ウェブ サービス(AWS 日本語)
というサービスを用意している。
今回はおれが使うのでRoute53について少し見ていきます。
Route53の使い方
とりあえず最低限動くまでのやるべき手順だけ書くと以下の通りになる。
- まずはつなぎたいサーバのIPアドレスを確認する
- マネジメントコンソールでRoute53に移動
- Create Hosted Zoneを選択
- 右に出てくるところに、使いたいドメイン名を入れる(www.とかは入れない。xxxxx.jpとかxxxxx.com、という部分だけ)
- 作ったら出てくるNSレコードを全て記録しておく
- Create Record Setを選択
- 右に出てくるところのNameにwwwを、TypeはA - IPv4 Addressを、ValueにつなぎたいサーバのIPアドレスを入れてCreate
- ドメインを取得したサイトに行って、ネームサーバを設定するページに行く
- アドレスを入れろと言われるので、先ほど記録したNSレコードを貼り付けて保存(※ 最後のピリオドを取らないとエラーになる)
- 設定が反映されるまで待つ
何をやったのか
Route53はDNSサーバを作れるサービスなので、まずは使いたい名前でDNSサーバを立てる。
そうするとそのURLが発行されるので、これをDNSサーバとして使うよ、とドメイン取得サービスの方に伝える。
立てたDNSサーバに、自分に対するアクセスをどこに振り分けるかを指定してやる(IPアドレスを教える)
こうすることで、ドメインから自分が立てたRoute53のDNSサーバにアクセスが行き、Route53のDNSサーバから指定したIPアドレスにアクセスが行く、という流れになるので、指定したドメイン名で指定したサーバが表示されるようになる、という感じ。
Route53に移管とはなんだったのか
アクセスがあったときにどのIPアドレスを見に行くかを決める場所を、ドメイン取得サービスが提供しているものからRoute53に切り替えましょう、という話だったので実はもうあまり解説することがない。上述の手順が移管にあたります。
AとかCNAMEとかって何
ちゃんと調べきれてないけど、ざっくりこんな感じみたい。
Aレコードは、ドメインにアクセスしてきた人がどのIPアドレスを見るか、というのを指定するもの。 Aレコードは一つしか指定できないが、IPアドレスは複数指定できるらしい。
CNAMEは、Canonical Nameのことで、「この名前できたら実際にはここを見てね」というもの。 CNAMEで設定したURLにアクセスすると、指定したURLに飛ばしたりする。
こっちの方がわかりやすいかも。
ApacheとNginxとPassengerとUnicornの違い【すごい初心者向け】
Amazon EC2の上でRailsアプリケーションを動かそうとして、サーバーを構築しようとしているのだけれど、Apache, Nginx, Passenger, Unicornなど色々な名前が出てくるものの、それぞれの役割がどう分担されているのかが分かりづらいのでメモすることにした。
自分も初心者に毛が生えた程度なので正確性はあんまり保証できないけど分かりやすさ重視でがんばってまとめたよ。
単純にサーバーを立ち上げて動きさえすればよいのであれば、
あたりを参考にすると良さそう。
この記事の対象読者
- Webサーバってなにそれ?おいしいの?
- さくらVPSとかEC2とかで泣きながらApacheの設定したことあるけど全く理解してない
- ぐぐればぐぐるほど意味がわからなくなったのであきらめてる
- Ruby on Railsをやろうとしているかherokuとかではすでにアプリを公開している
という感じのレベルの人。
すごく当たり前っぽいことも解説したりするし、正確性よりも比喩での分かりやすさを優先したりしているので、わかってる人には冗長かつ曖昧に感じる記述も多いかも。
とはいえ自分も勉強しながら書いているので、明らかに不適切なたとえだったりしたらご教示いただけると嬉しいです。
ことば
サーバ (Server)
プログラムとかファイルを保存しておいたり実行したりできるもの。
お手持ちのMacやWindowsそれ自体もサーバとして動かすことができたりする。さくらVPSやEC2は、仮想空間で作ったサーバを外部に向けて貸し出している。
Webサーバ (Web Server)
HTTPリクエストを受け取ったときに、なんらかの反応を返すプログラム。
例えば、localhost/index.htmlにアクセスされると、サーバー内のindex.htmlファイルの中身を返す、という感じ。 VPSやEC2などのサーバにWEBサーバを立てると、そのサーバで外部に向けてWebサイトを公開したりできる。
Rack
Rubyアプリケーションで、URLを生成するときに使われるしくみ。
PHPなどと違って直接ファイルを参照しない場合に、URLに合わせてどの順番でどのファイルを参照するか、などを管理してくれる。RailsではURLに沿って直接ファイルを参照したりしないので、routes.rbで指定された通りにファイルを経由してviewを表示するという経過をたどるわけですが、その裏ではRackの恩恵に与っているわけです。
もうちょっと詳しく知りたい人はこちらがよさそう。
Rack Webサーバ(Rack Web Server)
RubyアプリケーションとWebサーバをつなぐための中間サーバ、として扱われることが多い。
通常のWebサーバはRackのような機能をサポートしていないが、Rack Webサーバを挟むことで、RubyアプリケーションなどをWebサーバ上で動作させることができる。
Rack Webサーバ単体でも機能するにはするみたいだけど、Apacheなどの既存のWebサーバはレスポンスの処理がうまいので、それらと組み合わせて使うことが多いらしい。
モジュール (※Webサーバにおけるモジュール)
デフォルトのWebサーバの機能にはないものを、外部から取り込んで使えるようにするもの。
ApacheとNginxとPassengerとUnicornの違い
ApacheとNginxはWebサーバ
Apache
すごく有名で広く使われているオープンソースのWebサーバ。
ドキュメントがwebにいっぱい落ちている。デフォルトの設定だとRailsアプリは使えない。
Nginx
エンジンエックスと読むらしい。すごい優秀なWebサーバ。
以下のsion_cojp氏によるベンチマークを見る限り、Apacheよりかなり速そう。
Apacheと同じくデフォルトだとRailsアプリは使えない。
ApacheとNginxの共通点
ApacheとNginxの違い
- Apacheは古くから使われていてドキュメントが多い
- Nginxは比較的速くて高負荷に強い
PassengerはApacheやNginxで使えるモジュール
Passenger
Phusion Passenger(非公式にはmod_railsとmod_rackともいう)はApache HTTP Server及びnginx用のフリー・モジュールである。
すごくざっくりいうと、ApacheやNginxをちょっと改造してRackアプリ(Railsアプリ)にも対応できるようにしてしまうモジュール。
Apacheとは比較的組み合わせやすい。
Nginxと組み合わせる場合は、ソースコードを改造してコンパイルしなければいけないとのことで、ちょっとめんどくさそう。
UnicornはRack Webサーバ
UnicornはそもそもRackアプリに対応するために作られたRack Webサーバで、単体でも動作する模様。なんだけど、公式が
Designed for Rack, Unix, fast clients, and ease-of-debugging. We cut out everything that is better supported by the operating system, {nginx}http://nginx.org/ or {Rack}http://rack.github.io/.
(超絶意訳:RackとUnixと高速なクライアント向けに簡単にデバッグできるように作ったよ。nginxとかRackとかOSと相性が良くなるように調整したよ。)
と言っているのもあり、nginxと組み合わせて使うことがほとんどのようだ。
Unicorn Workerというものを使ってリクエストに対応しているらしく、サーバのダウンタイムなしでデプロイできるのが強みらしい。
ThinやPumaなども含めてRackアプリの総合的な比較などをしている記事があったので、もっと詳しく知りたい方はどうぞ
ということでNginx + Unicornを使うことにした
なんか速そうなのと、ダウンタイムなしでのデプロイというのが魅力的なので、自分はNginx + Unicornを使うことにします。
標準的なAmazon EC2環境でのNginx + Unicorn環境構築も、既存記事などに過不足を感じれば作るかもしれません。
ということで、Railsアプリ関連のサーバ構築に関する悩みが少しでも解消されれば幸いです。