夏コミにシナリオ書いたSF同人ゲーム出すので来て
2年前から「Everett Effect」というタイトルの同人ゲームを知人と作ってまして、このたび完成させて今度の夏コミに出す事になりました。
8月10日金曜日(1日目) 西ゆ37aです。 西館なのですこしアクセス悪いですが、よかったらお越しください。
C94にてSFビジュアルノベル『EVERETT EFFECT』完成版を頒布します! 今回はメディア非同梱のダウンロードパッケージ(1,000円)となります。 金曜西ゆ37a Sapience にてお待ちしております! #C94新刊 pic.twitter.com/71kCqfCtXq
— エヴェレットエフェクト@完成版!/金曜日西ゆ37a (@EverettEffect) August 4, 2018
ゲームの内容としては、中学生が科学コンクール(日本学生科学賞+どっかの大学の公開講座…の発展系みたいなやつ?)であるところの朝宮科学賞(ともみやかがくしょう、って読みます)に参加して、いろいろ実験してみたらフシギな現象があって…という感じです。
相方のユミズタキス君とは結構長い付き合いで、今回は彼が色々調べてきた心理学的なアプローチも用いて、かなり挑戦的な分岐システムを導入したりしてます。
また、今回はじめてゲームのシナリオというのを書いてみたんですが、総量12万字強と同人としてはまずまずの分量になりました。 ちゃんと書いたので読み応えもあると思います。
かくいう僕自身が中学時代は科学部で、こんな科学研究が送れてたらなぁという夢あるいはルサンチマンの昇華のようなところもありつつ、当時からこっそり溜めてきた現代先端物理学のネタをこれでもかと入れていったので、物理好きの方には特に楽しんで頂ける内容になったのではないかと思います。
商業じゃなかなかできそうにない挑戦的要素にあふれた作品になってますので、是非お手にとって遊んで頂けましたら幸いです。
後ほど何処かのサイトでDL版の配信もしようと思ってますが、その際は上記ツイッターアカウント @EverettEffect でアナウンスしていきますので、ツイッターやってる方はよかったらフォローとかして頂けますと大変幸いです。
……まだ完成してないのでこの後も作業続けます^^
Laravel(5.4)で、バリデーションエラーをフォームにリッチに表示したい時のサンプル(laravelcollective/Forms&HTML使ってる場合)
今日ふとした案件でLaravel触ってみたのですが、Railsのsimple_formにあるような、モデルのバリデーションでコケてる場合にinput要素のクラスにhas-error
を足す良い方法が見当たらなかったので、ざっと作ってみました。
// app/Helpers/FormHelper.php <?php namespace App\Helpers; class FormHelper { public static function text($name, $errors, $options=[]) { if( empty($options['class']) ){ $options['class'] = ''; } if( ! empty($errors->first($name)) ){ $options['class'] .= ' has-error'; } return \Collective\Html\FormFacade::text($name, null, $options); } }
まず、これが今回のメイン。オプションでclass渡してないときに先頭に半角スペース入るけど、別に害がないのでこのままで良いかなと思ってる。
text以外にも使いたいものがあれば適宜勝手に定義すると良いです。 (PHPのメタプログラミングについて調べるほどの情熱はなかった)
次に、このクラスにalias貼る。
// config/app.php // 'aliases' => の後に以下をそれっぽく追加 [ 'FormHelper' => App\Helpers\FormHelper::class, ]
ここまで来たら、あとはblade viewの中から使うだけ。
// form.blade.php // こんな風に使う {!! Form::model($inquiry, ['route' => ['inquiry.preview'], 'method' => 'put']) !!} <div class="form-group"> {!! Form::label('title', 'Title') !!} {!! FormHelper::text('title', $errors, ['class' => 'form-control']) !!} </div> <div class='form-group'> {!! Form::submit('プレビュー', ['class' => 'btn btn-primary form-control']) !!} </div> {!! Form::close() !!}
ちなみに当然だけどコントローラ側で ['inquiry' => new Inquiry]
っぽいことする必要はある。
モデル必要なければ Form::model じゃなく Form::open 使えば良いだけ。
明示的に $errors を渡してるのがダサい。 $errors
の取得については、もっと賢い方法があるかもしれません。 Laravelに詳しい人いたらコメントくれると嬉しいです。
以下、参考にしたリファレンスなど:
docker公式イメージのタグのリストを取得する
元ネタの記事は以下のものです。
DockerHubのイメージのタグ一覧をコマンドで取得する | Mazn.net
本記事は、ちょっとだけ説明を足したり自分の環境向けにコマンドを弄ったメモです。
yumみたいに簡単なコマンドがないか調べたんだけど公式の方法は用意されてないみたいなので以下のようにする。
僕はMacOSX上のzshで実行してるけど、まぁマトモなシェルが動く環境なら動くんじゃないかな。
curl -s https://registry.hub.docker.com/v1/repositories/php/tags | json_pp | grep name | grep 5.6.30
この例では、公式のphpイメージ https://hub.docker.com/_/php/ のタグをリストアップして、その中で名前に5.6.30を含むものを表示している。
phpの部分に別なパッケージ名を入れれば別なパッケージ向けで動くみたい。
json_pp は入れとくと便利なので入れておくと良い。
meta_tags を使ってRailsアプリを楽にOGP対応する時のサンプル
表題の通りの事をやりたいケースって多いと思うんですが、いまいち分かりやすいサンプルが見当たらないので、ざっと書いとく。
やりたいことは、重複コードをなるべく減らして、楽にOGP対応すること。ついでに面倒なmetaタグのtitleとdescriptionも良い感じに設定すること。
前提
# Gemfile にて gem 'meta_tags'
で、bundle (install) しとく。
# application.html.slim とかのレイアウトファイルで以下。 _header.html.slim とかに分離してたらそっち。 ruby: og = { url: request.original_url, type: 'website', # こう書くとtitleメソッドで入れたのが使われるらしい title: :title, site_name: 'OGPの下に出るサイトの名前', # 画像は置き場所にあわせて適宜 image: request.scheme + '://' + request.host + "/ogp.png", description: :description, } head = display_meta_tags site: 'デフォルトのサイトの名前', description: 'でふぉるとの説明文', fb: { app_id: ENV['FACEBOOK_APP_ID'] }, og: og
ogを変数に入れてるのは単に可読性の都合です。
あとは、個別のページのviewで以下のようにする。
# show.htm.slim ruby: # まぁ何か以下のような感じで使いたい変数を入れる。 title @product.name description @product.description set_meta_tags og: { image: @product.image.url }
注意事項とか
こうすると、 (ブラウザのタイトルバーに出る) title 要素には "デフォルトのサイトの名前 - #{@product.name}"
と出る。しかし、OGPのタイトルの部分には @product.name
が出る。
ここはOGPとブラウザで役割違うと思うし、僕はこれで良いと思ってこうしてるんだけど、両者を併せたい場合はちょっと面倒。 以下のモンキーパッチが使えそう。
Open Graph og:site_name getting merged with title · Issue #119 · kpumuk/meta-tags · GitHub
Sunspot (RailsでSolrによる検索を動かすGem)をとりあえず日本語検索に対応する方法
日本語で割と最近っぽい情報が全然なかったので簡単にメモ。
Solr: 6.6.0 / 7.0.0
Sunspot: 2.2.7
<RAILS_APP>/solr/configsets/sunspot/conf/schema.xml
の中で <fieldType name="text"
から始まって </fieldType>
で終わる部分を以下の内容に差し替える。
<fieldType name="text" class="solr.TextField" omitNorms="false" positionIncrementGap="100" autoGeneratePhraseQueries="false"> <analyzer> <tokenizer class="solr.JapaneseTokenizerFactory" mode="search"/> <filter class="solr.JapaneseBaseFormFilterFactory"/> <filter class="solr.JapanesePartOfSpeechStopFilterFactory" tags="lang/stoptags_ja.txt" /> <filter class="solr.CJKWidthFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ja.txt" /> <filter class="solr.JapaneseKatakanaStemFilterFactory" minimumLength="4"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType>
stopwords_ja.txt 及び stoptags_ja.txt は solrをapache.orgから solr-7.0.0-src.tgz
みたいなファイルをダウンロードしてきて 、その中にある solr-7.0.0/solr/core/src/test-files/solr/configsets/_default/conf/lang
のうち _ja.txt
で終わるファイルを <RAILS_DIR>/configsets/sunspot/conf/lang
の中に入れれば良いみたい。
面倒ならとりあえずそれが必要な行を削っても、それなりには動く。
これをベースにtokenizerにuserDictionaryとか入れればユーザ辞書を使った検索とかも出来るっぽい。
今あまり時間がなくて雑なメモになってますが、もしもう少し丁寧に知りたい人がいたらTwitterのメンションとか、ここへのコメントくれれば追記します。
CloudFront配下にRailsを置いたときにSSL対応するMiddleware
最近CloudFront配下にアプリケーションサーバーを置くのが徐々に流行ってる気がします。
想定する構成としては、ブラウザが直接叩くのがCloudFrontで、その直下にELB、そのさらに下に直接pumaというような形式。 nginx使わないパターンですね。 assets以下はどのみちCloudFrontでキャッシュされるから、nginxで高速化するまでもないっていうのがこの設計の思想かなと思ってます。 pumaが重くならない程度に同時接続数を制御する役割もELBがになってくれますし。
さて、ともかくそんな構成にすると、SSL対応で手間取ったのでメモ。
バージョンは以下の想定です。
- Rails 5.1.2 (4系でも変わらないとは思います)
- Puma 3.7
困ること
何が困るかというと、CloudFrontでSSL→HTTPに変換して、ELB以降はずっとHTTPで取り回すと、X-Forwarded-Protoヘッダが渡ってこない事です。CloudFrontは何故か独自のCloudFront-Forwarded-Protoというヘッダを渡してきます。
これによって、 force_ssl!
も動かないし、そもそも post,put,patchリクエストはCSRFをブロックする機構によって弾かれてしまいます。
フロントがELBだったら問題ないんですが、ここでは最前面にCoudFrontを置く想定…。
ここで対策は2つあります。
ここでは後者を採用しました。
やったこと
以下のRack Middlewareを用意します。
# lib/cloud-front-header.rb class CloudFrontHeader def initialize(app) @app = app end def call(env) cf_proto = env['HTTP_CLOUDFRONT_FORWARDED_PROTO'].to_s if cf_proto && cf_proto.length > 0 env['HTTP_X_FORWARDED_PROTO'] = cf_proto end @app.call(env) end end
そして、 application.rb に以下の内容を足します。 他にmiddleware使ってない場合は、どこに書いても問題ないと思います。
# config/application.rb module MyApp class Application < Rails::Application # 前略 require './lib/cloud-front-header.rb' config.middleware.use CloudFrontHeader # 後略 end end
と、強引な方法ではありますが、 CloudFront-Forwarded-Proto を勝手に X-Forwarded-Proto に上書きするという荒技でどうにかしたのでした。
Rack Middleware がバグるのは鬱陶しいので、to_s等を使った防衛的なコードになってますが、気に入らない人は適宜書き換えると良いです。
あと、置き場所を考え直すと require は要らないかも知れないです。 もし良い方法あったら誰かコメントとかで教えてください。
こういう事が出来るのはRackの優れたレイヤアーキテクチャのたまものですね。
Rails5で簡単にモバイル/PCのビュー分岐を行う
最近、仕事で必要だったので。 だいたい以下の記事を元にしてるだけですが、ちょいサンプルコードなど含めて解説。
元々は mobylette というgemを使おうとしたらRails5では(たぶん4でも?)コケちゃうので自前実装気味に済ませたって経緯がある。
想定するサービス
基本はレスポンシブだけどTOPページ等の一部の画面だけPC/モバイルでの分岐をしているようなサービス
方法
まず、以下のconcernsを作る。
# app/controllers/concerns/respond_to_mobile_requests.rb require 'active_support/concern' module RespondToMobileRequests extend ActiveSupport::Concern # Regexp From: https://gist.github.com/dalethedeveloper/1503252/931cc8b613aaa930ef92a4027916e6687d07feac MOBILE_REGEXP = /Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/ included do before_action :variant_mobile def variant_mobile # The solution from: https://stackoverflow.com/questions/39495834/mobile-view-in-rails-5 request.variant = :mobile if is_mobile_request? end def is_mobile_request? @_is_mobile_request ||= MOBILE_REGEXP.match request.user_agent end end end
次に、描画を振り分けたいコントローラおよびそこのアクションで以下のようにする
# app/controllers/home_controller.rb class HomeController < ApplicationController include RespondToMobileRequests def index if is_mobile_request? # モバイルの時だけの処理 else # PCの時だけの処理 end # 以下のコードでビュー振り分け respond_to do |format| format.html.mobile format.html end end end
あとはビューファイルとして index.html.erb
(※hamlでもslimでもご自由に)と index.html+mobile.erb
を作れば、勝手にビューを振り分けてくれる。
もしCloudFrontのカスタムヘッダ( CloudFront-Is-Mobile-Viewer
等)とかを使いたければ、request.user_agentにmatchかけてる部分の代わりに request.headers['CloudFront-Is-Mobile-Viewer']
等を見ればいいと思う。