この記事の続きです
ユーザー登録からログインまでをマテリアルデザインでいい感じの見た目になるところまで目指します。
まず
ざっくりと流れを考えると、
のような感じになると思います
まず http://localhost:3000/users/sign_up にアクセスすると、webpackerを消したので以下のようなエラーが出ます。
undefined method `javascript_pack_tag' for #<#<Class:0x00007fca896de970>:0x00007fca896d2af8>
assetsはwebpackで管理するようにするのでlayouts/application.html.erbを修正します
<!DOCTYPE html> <html> <head> <title>Alder</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> - <%= stylesheet_link_tag 'application', media: 'all' %> - <%= javascript_pack_tag 'application' %> </head> <body> <%= yield %> </body> </html>
でました。シンプルで良いですね(よくない)。
ところで、webpackerは普通にwepack.config.jsを使えるようにしてさえくれたら喜んで使う人は多いと思いますが、なんであんな風なんでしょうね。
deviseのviewをgenerateします
$ bundle exec rails generate devise:views invoke Devise::Generators::SharedViewsGenerator create app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for create app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb create app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions create app/views/devise/sessions/new.html.erb create app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb create app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb
いまのままではUserモデルに追加したdisplay_nameがprecense: trueなのでユーザー登録ができません。
Display name can't be blank
フォームに以下を追加しておきます
<%= f.label :display_name %><br /> <%= f.text_field :display_name %>
ということはstrong_parameterもいじらないといけないのでdeviseのcontrollerもgenerateします
と思ったんですが、ApplicationControllerにメソッドを追加すればいいんでした。ドキュメントに書いてましたね。
class ApplicationController < ActionController::Base + before_action :configure_permitted_parameters, if: :devise_controller? + protected + def configure_permitted_parameters + devise_parameter_sanitizer.permit(:sign_up, keys: [:display_name]) + end end
登録からログインまで動作も問題ありませんでした。
続いてwebpack導入です
$ yarn add webpack $ yarn add webpack-cli
yarn dev でdevelopment用にビルド、yarn build でproduction用にビルドできるように、package.jsonにscriptsを追加しておきます。
{ "name": "alder", "private": true, "dependencies": { "@rails/actioncable": "^6.0.0-alpha", "@rails/activestorage": "^6.0.0-alpha", "@rails/ujs": "^6.0.0-alpha", "webpack": "^4.41.1", "webpack-cli": "^3.3.9" }, + "scripts": { + "build": "webpack --mode=production", + "dev": "webpack --mode=development" + }, "version": "0.1.0" }
つぎはwebpack.config.jsです。ちゃんとやるとしんどいポイントなので、とりあえず動くところまでやります。
const ManifestPlugin = require('webpack-manifest-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const path = require('path'); module.exports = { context: path.resolve(__dirname, 'app', 'javascript', 'packs'), entry: { application: './application.js', }, output: { path: path.resolve(__dirname, 'public', 'packs'), filename: '[name]-[hash].js' }, plugins: [ new ManifestPlugin({ fileName: 'manifest.json', publicPath: '/packs/', writeToFileEmit: true, }), new MiniCssExtractPlugin({ filename: 'css/[name]-[hash].css', chunkFilename: '[id].css', ignoreOrder: false, }), ] };
というわけでマニフェストとCSSを良い感じに使いたいのでプラ銀追加します。
$ yarn add webpack-manifest-plugin $ yarn add mini-css-extract-plugin
webpackerが生成したapplication.jsをエントリーポイントにしておきます。application.jsの中身はとりあえず以下です。
console.log('hello work')
続いて、RailsのViewから読み込めるようにヘルパーメソッドを作ります。
module WebpackBundleHelper class BundleNotFound < StandardError; end def asset_bundle_path(entry, **options) raise BundleNotFound, "Could not find bundle with name #{entry}" unless manifest.key? entry asset_path(manifest.fetch(entry), **options) end def javascript_bundle_tag(entry, **options) path = asset_bundle_path("#{entry}.js") options = { src: path, defer: true }.merge(options) if options[:async] options.delete(:defer) end javascript_include_tag '', **options end def stylesheet_bundle_tag(entry, **options) path = asset_bundle_path("#{entry}.css") options = { href: path }.merge(options) stylesheet_link_tag '', **options end private def manifest return @manifest if @manifest @manifest ||= JSON.parse(File.read(Rails.root.join('public', 'packs', 'manifest.json'))) end end
これでmanifest.jsonからハッシュ値付きのファイル名を解決できるようになるはずです
<!DOCTYPE html> <html> <head> <title>Alder</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> + <%= javascript_bundle_tag 'application' %> </head> <body> <%= yield %> </body> </html>
ビルドします
$ yarn dev yarn run v1.19.0 $ webpack --mode=development Hash: 0a5a7288b52342b5060e Version: webpack 4.41.1 Time: 104ms Built at: 10/13/2019 1:13:00 PM Asset Size Chunks Chunk Names application-0a5a7288b52342b5060e.js 4.54 KiB application [emitted] [immutable] application manifest.json 68 bytes [emitted] Entrypoint application = application-0a5a7288b52342b5060e.js [./application.js] 752 bytes {application} [built] Done in 1.28s.
うまくいってそうですね。
$ cat public/packs/manifest.json { "application.js": "/packs/application-0a5a7288b52342b5060e.js" }
ブラウザで開いていたタブをリロードするとコンソールに
hello work
と表示されました。webpackの導入はこれで(とりあえず)OKです。
キリが良いのでいったんここで記事を切ります。