niki12260714の日記

フリーランスのITエンジニアの呟き。

配布のBootstrapテンプレートをRailsに導入する

世の中には親切な人が多いもので、格好いいBootstrapのテンプレートを配布している人がいます。
有料のものなんかサポートも付いていたりして、デザインセンスが壊滅的な人にはありがたい世の中です。
で、このテンプレートをRailに適用するにはどうしたらいいの? というお話です。
テンプレートをダウンロードしてくると、そのままサイトに使えるようにBootstrapのフォルダも入っていたりして、いやでもRailsのgemで入れてるから、これ要らないよねってなって、では、なにを適用するのか? って話になります。
全部が全部に対応するわけではないでしょうが、自分がハマったポイントを、後のメモとして残します。

【Bootstarapのバージョン確認】
適用するBootstrapのバージョンを確認します。
バージョンによって、gemを変更。
3ならbootstrap-sass、4ならbootstrapを導入。

【scssファイルをapp/assets/stylesheetsに配置、読み込み順を制御】
デフォルトのBootstrapに上書きする形でscssがあったので、それを「app/assets/stylesheets」以下に配置します。
で、これをrails -sすると、なんにもしてないと、Railsが配下にあるscssを順番関係なく全部コンパイルしてしまい、mixinが後に読まれて「そんな変数ないよ」と怒られたりします。
なので、application.cssを開いて、読み込み順を制御します。
「*= require_tree .」が、「このフォルダ以下を全部読み込み」という意味なので、ここを削ります。
代わりに、「*= require custom.css」のように、読み込みたいcssを、読み込みたい順番に上から記述していきます。

【その他、jsファイル、cssファイルをvendor/assetsに配置】
Bootstrap、JQuery以外の、適用テンプレート独自のjsファイル、cssファイルは、まとめてvendor/assets以下に配置します。
ここはアセットパイプラインがデフォルトで通されるところらしいです。
でも通らなかったら、以下を参照にapplication.rbに記述を追加、確認します。

masaqu.id

ここまでで、自分は適用できました。
以下、自分が一番ハマったポイント。

【モバイル画面のために、metaタグを記述する】
Chromeディベロッパーツールを使ってモバイルで見ても、画面の文字が大きくならない。
cssを見ると、画面サイズに応じてフォントサイズを変える記述があるのにおかしい。
なので、テンプレートに含まれていたサンプルページのソースコードを見て、自分の記述との差異を確認したら、以下が違ってました。

<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

これを外してモバイルで見ると、文字が小さくなる。
入れると、狙った通りにフォントサイズが変わる。
このタグはモバイルを対象とするページでは必ず入れないといけなかったらしい。

getbootstrap.com

上記ページの「Mobile first」ってところです。
で、viewportってなんだろうと調べると、こちらが詳しかったです。

tech.nitoyon.com

これで適用終了です。

※gemでBootstrap入れてますけど、これを止めて、Railsフォルダに諸々一式置く方法もあります。
自分は試してないんですけど、vendor/assets以下に置いてコンパイル通せばいけるんじゃないかと予想。

MySQLでソートを任意に制御する方法

文字列でソートする場合、普通にやると「AaBbCc」と並びますが、これを「ABCabc」とソートした場合のやり方。
MySQLはソートにcaseを使えるので、それを利用します。

ORDER BY CASE
 WHEN ソート文字列 REGEXP '[A-Z]' then 0
 WHEN ソート文字列 REGEXP '[a-z]' then 1
 ELSE 99
END ASC

REGEXP正規表現を利用して大文字A~Zとの一致を示しています。
こうやって大文字、小文字に重みを振り分ければ、任意の順番にソートが可能。

AWS Cloud9 + Rails + MySQLで絵文字を扱う

参考にしたのはこちら。

qiita.com

というわけで、MySQL文字コードを確認するわけですが、そっちは既に「utf8mb4」でした。
でもrailsの方で文字コードを「utf8」にしていたので、rake:dbした時にutf8でテーブル作ってしまっていたようなので、これを修正します。

/config/database.ymlを以下のように設定

default: &default
 adapter: mysql2
 charset: utf8mb4
 encoding: utf8mb4
 collation: utf8mb4_unicode_ci
 reconnect: false
 pool: 5
 host: localhost

次にMySQLでAlter tableをします。

alter table (テーブル名) convert to character set utf8mb4;

が、ここでエラー。
「Specified key was too long; max key length is 767 bytes」

ぐぐったら、こちらに原因と修正方法がありましたので、参考にしました。

nabeatsu.hatenablog.com

「sudo vi /etc/my.conf」で以下を追加

innodb_file_format=Barracuda
innodb_file_format_max=Barracuda
innodb_file_per_table=1
innodb_large_prefix=1

「sudo /etc/init.d/mysqld restart」でMySQLを再起動

再びMySQLに入り、

alter table (テーブル名) ROW_FORMAT=DYNAMIC;
alter table (テーブル名) convert to character set utf8mb4;

これで文字コードがutf8mb4に変わり、絵文字が入ります。

AWS Cloud9でMySQLに乗り換える

諸事情により、ポスグレからMySQLにDBを変更することになり、開発環境のDBを変えることになりました。
その手順です。

※2018/7/30現在、AWS Cloud9には、MySQLが標準でインストールされているので、インストール作業は飛ばします

MySQLにデータベースを作る】

参考にしたのはこちら。

qiita.com1.文字コードを修正する
「sudo vi /etc/my.cnf」で、my.confに「character-set-server=utf8mb4」を追加
※sudoでやらないと権限足りなくて書き込みできませんでした
2.開発用、テスト用、本番用のデータベースを作る
mysql -uroot」でmysqlに入り、「create database DB名;」でそれぞれデータベースを作成
3.接続用のユーザーを作成し、作成したデータベースへの権限を不要
「create user 'ユーザー名'@'localhost' identified by 'パスワード';」でユーザー作成
「grant all on DB名.* to 'ユーザー名'@'localhost' identified by '接続パスワード';」

MySQLのgemを入れる】

Gemfileに「gem 'mysql2'」を追加、「bundle install」
→失敗する。
 「Gem::Ext::BuildError: ERROR: Failed to build gem native extension.」の表示
ぐぐってみると、こちらの記事がヒット。

kzy52.com

「sudo yum -y install mysql-devel」を実施後、「bundle install」「bundle update」でエラーが発生しなくなる

【database.ymlを修正】

こちらの記事の設定をそのまま使わせていただきました。

www.rubylife.jp

【DB作成しなおし】

「bundle exec rake db:migrate」を実行。
→エラー発生、「NoMethodError: undefined method `inet' for #<ActiveRecord(略」が発生
ぐぐると、こちらの記事がヒット。

programming-beginner-zeroichi.jpまったく同じ状態だったので、inetをstringに修正、再度「bundle exec rake db:migrate」を実施、成功。

ここまで来たら、「rails s -b $IP -p $PORT」でrails serverを起動し、ログイン画面を表示させ、ログインを試しました。
当然ユーザーがいないので蹴られます。
DBにユーザーを問い合わせられる(接続が確立している)、ユーザーがいない(新しいDBを見に行っている)から、成功していると判断。
以上終了です。

deviceでtwitter連携時に「raise OAuth::Unauthorized, response 403」となった時の対応方法

deviceの使い方はこちら参照。

qiita.com

で、この通りに進めて、サインアップページの下に出てくる「Sign in with Twitter」をクリックすると、

「raise OAuth::Unauthorized, response 403」

となってしまいました。
ぐぐると、「Twitterの設定で、Callback URLが空だと駄目」とあります。
ですが、自分はちゃんと埋めてある。
とすると、Callbackが正しくないということで、「rails routes」でルート確認。

f:id:niki12260714:20180718093640j:plain

deviceが自分で作ってくれたルートの中に、twitter関連のものと思われるものを発見。
これをそれぞれ、TwitterのCallback URLに追加。

https://(自分の環境)/users/auth/twitter
https://(自分の環境)/users/auth/twitter/callback」

これで自分はエラーは出なくなりました。

独自定義のモデルを元にしたformのvalidatesを日本語化

変にハマったので、メモ。
内容はここの続きです。
あと、大前提として、「i18n」を入れて、日本語化の準備が出来ていることが必須です。

niki12260714.hatenablog.com

この方法で戻ってくるエラーメッセージを見ると
「col aは必須です」
のように、モデルに定義したattributesは英語になってます。
これを日本語にするには、「config/locals/models」の中に「ja.yml」を作成し、以下のように記述します。

ja:
 activemodel:
  attributes:
   item_add:
    col_a: "カラムA"
    col_b: "カラムB"
    col_c: "カラムC"

ネットでぐぐって最初にヒットするのは、大体がDBと結びついたモデルのカラム名を日本語化する話だと思います。
自分の場合、独自モデルで、Active Modelを継承したものなので、activemodelと記述しないと駄目です。
気付けば、そういうことか! ってなる話でした。

※これで日本語化されてないとなると、多分パスが通ってない気がするので、こちらを参考にパスを通すと良いかと。

qiita.com

Active Modelを定義し、form_forを使用、validatesでエラー処理までの流れ

画面の入力項目が一つのテーブルだけではないというのはよくあるパターン。
そうすると、form_forが使えないので、form_tagを使うことになります。
が、そうするとvalidatesの処理とかセオリー通りにいかないし、form_forの方がBootstrapでごにょごにょするのに便利なわけですし。
なんで、こういう場合は「そのformで使うモデルを独自に定義し、それを使う」という技があります。
※あと、検索画面で「検索条件欄に入力が無かったらエラーにしたい」というのをvalidatesで定義しておきたいとか。

というわけで、独自モデルの定義。
railsが5以上の場合は、app/modelの下にconcernsというフォルダが出来ているので、ここを使うらしい?
※ファイルの配置位置は、私の解釈なんで、間違っていたらご指摘ください。
「item_add.rb」というファイルを追加し、以下を記述

【model】
class ItemAdd
 include ActiveModel::Model
 attr_accessor :col_a, :col_b, :col_c

 validates :col_a
  presence: true,
  length: {minimum: 1, maximum: 100}
end

ポイントは、赤字にした「include」のところで、ActiveModelを継承すること。
で、attr_accessorで、そのformで使う要素を列挙すること。
attr_accessorに書いた要素に対し、validatesを定義しておきます。
これは通常のModelに対する書き方と一緒。

で、この独自に定義したmodelをcontrollerでnewしてあげて、viewで使うわけです。

【controller】
def init
 #独自定義のモデルをロードする
 @add_form = ItemAdd.new()
end

【view】
<%= form_for @add_form, url: {controller: :xxx, action: :xxx} do |form| %>
 <%= form.label :col_a, "要素A" %>
 <%= form.text_field :col_a, id: :col_a%><br />
 <%= form.label :col_b, "要素B" %>
 <%= form.text_field :col_b, id: :col_b%><br />
 <%= form.label :col_c, "要素C" %>
 <%= form.text_field :col_c, id: :col_c%><br />
 <br />
 <%= form.submit "追加", class: :"btn btn-default" %>
<% end %>

これでview側で、form_forが使えます!
さて、これでsubmitされたら、validatesを通してチェックをしたいわけで、それはcontrollerでこんな感じで書きます。

【controller】
def xxx
 #入力値を元にモデルオブジェクトを生成
 add_form = ItemAdd.new(col_a: params[:item_add][:col_a], col_b: params[:item_add][:col_b], col_c: params[:item_add][:col_c])
 if !add_form.valid?
  #validatesでエラーになった場合の記述
  flash[:danger] = add_form.errors.full_messages[0]
 else
  #validatesに問題がない場合の記述
 end
end

ポイントは、赤字のnewしているところと、newしたオブジェクトに対し、valid?と判定をかけているところ。
newする時に、formでpostされたデータを入れてあげます。
その結果が正しいか(valid?)を確認し、falseが戻ってきたらエラーってことで、エラー処理を書けばよいです。
エラーのメッセージは、通常のmodelのvalidatesで戻されるのと同一です。

 

→エラーメッセージの日本語化について、追加の記事があります。

niki12260714.hatenablog.com