Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

Rails チュートリアルをやってみる(4) 2章を開始〜2.2まで

2章はscaffoldを使ってみるらしい。

さて、前回Railsのバージョンでかなりヒドい目に遭って、訳がわからなくなった。 恐らくは、rails newしたタイミングではbundle installが走ってはいけないのだと思う。 こんな記事もある

rails new でバージョン指定したのに上のバージョンになって困った話 - のえら

うん、たぶんそうすれば良かったんだな。

というか、このお勉強用ディレクトリのvendor/bundleにRailsのgemを入れるんであれば、最初から5.1.6をいれろやという話かもしれない。

なので、乱暴かもしれないが、お勉強用ディレクトリをrm -fr ./*して、Railsを入れ直すところからやることにする。

> bundle init
Writing new Gemfile to /Users/tambara/study/rails_study/Gemfile

> vi Gemfile 
> cat Gemfile 
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails", '5.1.6'

念のため、ここでもバージョンを指定しておこう。

> bundle install --path=vendor/bundle
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Fetching rake 12.3.1
Installing rake 12.3.1
Fetching concurrent-ruby 1.1.3
Installing concurrent-ruby 1.1.3
Fetching i18n 1.1.1
Installing i18n 1.1.1
Fetching minitest 5.11.3
Installing minitest 5.11.3
Fetching thread_safe 0.3.6
Installing thread_safe 0.3.6
Fetching tzinfo 1.2.5
Installing tzinfo 1.2.5
Fetching activesupport 5.1.6
Installing activesupport 5.1.6
Fetching builder 3.2.3
Installing builder 3.2.3
Fetching erubi 1.7.1
Installing erubi 1.7.1
Fetching mini_portile2 2.3.0
Installing mini_portile2 2.3.0
Fetching nokogiri 1.8.5
Installing nokogiri 1.8.5 with native extensions
Fetching rails-dom-testing 2.0.3
Installing rails-dom-testing 2.0.3
Fetching crass 1.0.4
Installing crass 1.0.4
Fetching loofah 2.2.3
Installing loofah 2.2.3
Fetching rails-html-sanitizer 1.0.4
Installing rails-html-sanitizer 1.0.4
Fetching actionview 5.1.6
Installing actionview 5.1.6
Fetching rack 2.0.6
Installing rack 2.0.6
Fetching rack-test 1.1.0
Installing rack-test 1.1.0
Fetching actionpack 5.1.6
Installing actionpack 5.1.6
Fetching nio4r 2.3.1
Installing nio4r 2.3.1 with native extensions
Fetching websocket-extensions 0.1.3
Installing websocket-extensions 0.1.3
Fetching websocket-driver 0.6.5
Installing websocket-driver 0.6.5 with native extensions
Fetching actioncable 5.1.6
Installing actioncable 5.1.6
Fetching globalid 0.4.1
Installing globalid 0.4.1
Fetching activejob 5.1.6
Installing activejob 5.1.6
Fetching mini_mime 1.0.1
Installing mini_mime 1.0.1
Fetching mail 2.7.1
Installing mail 2.7.1
Fetching actionmailer 5.1.6
Installing actionmailer 5.1.6
Fetching activemodel 5.1.6
Installing activemodel 5.1.6
Fetching arel 8.0.0
Installing arel 8.0.0
Fetching activerecord 5.1.6
Installing activerecord 5.1.6
Using bundler 1.17.1
Fetching method_source 0.9.2
Installing method_source 0.9.2
Fetching thor 0.20.3
Installing thor 0.20.3
Fetching railties 5.1.6
Installing railties 5.1.6
Fetching sprockets 3.7.2
Installing sprockets 3.7.2
Fetching sprockets-rails 3.2.1
Installing sprockets-rails 3.2.1
Fetching rails 5.1.6
Installing rails 5.1.6
Bundle complete! 1 Gemfile dependency, 38 gems now installed.
Bundled gems are installed into `./vendor/bundle`
> rails -v
Rails 5.2.1
> which rails
/Users/tambara/.rbenv/shims/rails
> bundle exec rails -v
Rails 5.1.6

あ、.ruby-versionも消えてしまったはずだ。 遅ればせながら、rbenv local 2.5.1もやり直しておく。

では、チュートリアルの2章の先頭からやっていこう

> bundle exec rails _5.1.6_ new toy_app --skip-bundle
      create  
      create  README.md
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
         run  git init from "."
Initialized empty Git repository in /Users/tambara/study/rails_study/toy_app/.git/
      create  app
      create  app/assets/config/manifest.js
      create  app/assets/javascripts/application.js
      create  app/assets/javascripts/cable.js
      create  app/assets/stylesheets/application.css
      create  app/channels/application_cable/channel.rb
      create  app/channels/application_cable/connection.rb
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/jobs/application_job.rb
      create  app/mailers/application_mailer.rb
      create  app/models/application_record.rb
      create  app/views/layouts/application.html.erb
      create  app/views/layouts/mailer.html.erb
      create  app/views/layouts/mailer.text.erb
      create  app/assets/images/.keep
      create  app/assets/javascripts/channels
      create  app/assets/javascripts/channels/.keep
      create  app/controllers/concerns/.keep
      create  app/models/concerns/.keep
      create  bin
      create  bin/bundle
      create  bin/rails
      create  bin/rake
      create  bin/setup
      create  bin/update
      create  bin/yarn
      create  config
      create  config/routes.rb
      create  config/application.rb
      create  config/environment.rb
      create  config/secrets.yml
      create  config/cable.yml
      create  config/puma.rb
      create  config/spring.rb
      create  config/environments
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/initializers
      create  config/initializers/application_controller_renderer.rb
      create  config/initializers/assets.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/cookies_serializer.rb
      create  config/initializers/cors.rb
      create  config/initializers/filter_parameter_logging.rb
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/initializers/new_framework_defaults_5_1.rb
      create  config/initializers/wrap_parameters.rb
      create  config/locales
      create  config/locales/en.yml
      create  config/boot.rb
      create  config/database.yml
      create  db
      create  db/seeds.rb
      create  lib
      create  lib/tasks
      create  lib/tasks/.keep
      create  lib/assets
      create  lib/assets/.keep
      create  log
      create  log/.keep
      create  public
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/apple-touch-icon-precomposed.png
      create  public/apple-touch-icon.png
      create  public/favicon.ico
      create  public/robots.txt
      create  test/fixtures
      create  test/fixtures/.keep
      create  test/fixtures/files
      create  test/fixtures/files/.keep
      create  test/controllers
      create  test/controllers/.keep
      create  test/mailers
      create  test/mailers/.keep
      create  test/models
      create  test/models/.keep
      create  test/helpers
      create  test/helpers/.keep
      create  test/integration
      create  test/integration/.keep
      create  test/test_helper.rb
      create  test/system
      create  test/system/.keep
      create  test/application_system_test_case.rb
      create  tmp
      create  tmp/.keep
      create  tmp/cache
      create  tmp/cache/assets
      create  vendor
      create  vendor/.keep
      create  package.json
      remove  config/initializers/cors.rb
      remove  config/initializers/new_framework_defaults_5_1.rb

リスト2.1にGemfileを書き換えて、bundle installする

> cd toy_app
> vi Gemfile
> bundle install --without production
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using rake 12.3.1
Using concurrent-ruby 1.1.3
Using i18n 1.1.1
Using minitest 5.11.3
Using thread_safe 0.3.6
Using tzinfo 1.2.5
Fetching activesupport 5.1.6
Installing activesupport 5.1.6
Using builder 3.2.3
Using erubi 1.7.1
Using mini_portile2 2.3.0
Using nokogiri 1.8.5
Using rails-dom-testing 2.0.3
Using crass 1.0.4
Using loofah 2.2.3
Using rails-html-sanitizer 1.0.4
Fetching actionview 5.1.6
Installing actionview 5.1.6
Using rack 2.0.6
Using rack-test 1.1.0
Fetching actionpack 5.1.6
Installing actionpack 5.1.6
Using nio4r 2.3.1
Using websocket-extensions 0.1.3
Fetching websocket-driver 0.6.5
Installing websocket-driver 0.6.5 with native extensions
Fetching actioncable 5.1.6
Installing actioncable 5.1.6
Using globalid 0.4.1
Fetching activejob 5.1.6
Installing activejob 5.1.6
Using mini_mime 1.0.1
Using mail 2.7.1
Fetching actionmailer 5.1.6
Installing actionmailer 5.1.6
Fetching activemodel 5.1.6
Installing activemodel 5.1.6
Fetching arel 8.0.0
Installing arel 8.0.0
Fetching activerecord 5.1.6
Installing activerecord 5.1.6
Using bindex 0.5.0
Using bundler 1.17.1
Fetching byebug 9.0.6
Installing byebug 9.0.6 with native extensions
Using coffee-script-source 1.12.2
Using execjs 2.7.0
Using coffee-script 2.4.1
Using method_source 0.9.2
Using thor 0.20.3
Fetching railties 5.1.6
Installing railties 5.1.6
Using coffee-rails 4.2.2
Using ffi 1.9.25
Using multi_json 1.13.1
Fetching jbuilder 2.7.0
Installing jbuilder 2.7.0
Fetching jquery-rails 4.3.1
Installing jquery-rails 4.3.1
Using rb-fsevent 0.10.3
Using rb-inotify 0.9.10
Using ruby_dep 1.5.0
Using listen 3.1.5
Fetching puma 3.9.1
Installing puma 3.9.1 with native extensions
Using sprockets 3.7.2
Using sprockets-rails 3.2.1
Fetching rails 5.1.6
Installing rails 5.1.6
Using sass-listen 4.0.0
Using sass 3.7.2
Using tilt 2.0.8
Fetching sass-rails 5.0.6
Installing sass-rails 5.0.6
Using spring 2.0.2
Using spring-watcher-listen 2.0.1
Using sqlite3 1.3.13
Using turbolinks-source 5.2.0
Fetching turbolinks 5.0.1
Installing turbolinks 5.0.1
Fetching uglifier 3.2.0
Installing uglifier 3.2.0
Fetching web-console 3.5.1
Installing web-console 3.5.1
Bundle complete! 15 Gemfile dependencies, 64 gems now installed.
Gems in the group production were not installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

あ、また~/.rbenvの下に入っちゃった。どうもよくわからないな・・・。まあ、しょうがない。続き。

> git add -A
> git commit -m 'Initialize repository'
(略)
> vi app/controllers/application_controller.rb
> vi config/routes.rb 
> git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   app/controllers/application_controller.rb
    modified:   config/routes.rb

no changes added to commit (use "git add" and/or "git commit -a")
> git add --all
> git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   app/controllers/application_controller.rb
    modified:   config/routes.rb

> git commit -m 'Add hello'
[master b08b557] Add hello
 2 files changed, 5 insertions(+), 1 deletion(-)
> heroku create
Creating app... done, ⬢ sleepy-tundra-20972
https://sleepy-tundra-20972.herokuapp.com/ | https://git.heroku.com/sleepy-tundra-20972.git
> git push heroku master
Counting objects: 90, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (76/76), done.
Writing objects: 100% (90/90), 20.00 KiB | 1.67 MiB/s, done.
Total 90 (delta 6), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote:  !     Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used.
remote:             Detected buildpacks: Ruby,Node.js
remote:             See https://devcenter.heroku.com/articles/buildpacks#buildpack-detect-order
remote: -----> Ruby app detected
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.4.5
remote: -----> Installing dependencies using bundler 1.15.2
remote:        Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
remote:        Warning: the running version of Bundler (1.15.2) is older than the version that created the lockfile (1.17.1). We suggest you upgrade to the latest version of Bundler by running `gem install bundler`.
remote:        Fetching gem metadata from https://rubygems.org/.........
remote:        Fetching version metadata from https://rubygems.org/..
remote:        Fetching dependency metadata from https://rubygems.org/.
remote:        Fetching rake 12.3.1
remote:        Fetching concurrent-ruby 1.1.3
remote:        Fetching minitest 5.11.3
remote:        Installing rake 12.3.1
remote:        Installing minitest 5.11.3
remote:        Installing concurrent-ruby 1.1.3
remote:        Fetching thread_safe 0.3.6
remote:        Fetching builder 3.2.3
remote:        Installing builder 3.2.3
remote:        Installing thread_safe 0.3.6
remote:        Fetching erubi 1.7.1
remote:        Installing erubi 1.7.1
remote:        Fetching mini_portile2 2.3.0
remote:        Installing mini_portile2 2.3.0
remote:        Fetching crass 1.0.4
remote:        Installing crass 1.0.4
remote:        Fetching rack 2.0.6
remote:        Installing rack 2.0.6
remote:        Fetching nio4r 2.3.1
remote:        Fetching websocket-extensions 0.1.3
remote:        Installing nio4r 2.3.1 with native extensions
remote:        Installing websocket-extensions 0.1.3
remote:        Fetching mini_mime 1.0.1
remote:        Installing mini_mime 1.0.1
remote:        Fetching arel 8.0.0
remote:        Installing arel 8.0.0
remote:        Using bundler 1.15.2
remote:        Fetching coffee-script-source 1.12.2
remote:        Installing coffee-script-source 1.12.2
remote:        Fetching execjs 2.7.0
remote:        Installing execjs 2.7.0
remote:        Fetching method_source 0.9.2
remote:        Installing method_source 0.9.2
remote:        Fetching thor 0.20.3
remote:        Installing thor 0.20.3
remote:        Fetching ffi 1.9.25
remote:        Fetching multi_json 1.13.1
remote:        Installing multi_json 1.13.1
remote:        Fetching pg 0.20.0
remote:        Installing ffi 1.9.25 with native extensions
remote:        Installing pg 0.20.0 with native extensions
remote:        Fetching puma 3.9.1
remote:        Installing puma 3.9.1 with native extensions
remote:        Fetching rb-fsevent 0.10.3
remote:        Installing rb-fsevent 0.10.3
remote:        Fetching tilt 2.0.8
remote:        Installing tilt 2.0.8
remote:        Fetching turbolinks-source 5.2.0
remote:        Installing turbolinks-source 5.2.0
remote:        Fetching tzinfo 1.2.5
remote:        Installing tzinfo 1.2.5
remote:        Fetching nokogiri 1.8.5
remote:        Installing nokogiri 1.8.5 with native extensions
remote:        Fetching i18n 1.1.1
remote:        Installing i18n 1.1.1
remote:        Fetching websocket-driver 0.6.5
remote:        Installing websocket-driver 0.6.5 with native extensions
remote:        Fetching mail 2.7.1
remote:        Installing mail 2.7.1
remote:        Fetching rack-test 1.1.0
remote:        Installing rack-test 1.1.0
remote:        Fetching sprockets 3.7.2
remote:        Installing sprockets 3.7.2
remote:        Fetching coffee-script 2.4.1
remote:        Installing coffee-script 2.4.1
remote:        Fetching uglifier 3.2.0
remote:        Installing uglifier 3.2.0
remote:        Fetching turbolinks 5.0.1
remote:        Installing turbolinks 5.0.1
remote:        Fetching rb-inotify 0.9.10
remote:        Installing rb-inotify 0.9.10
remote:        Fetching activesupport 5.1.6
remote:        Installing activesupport 5.1.6
remote:        Fetching sass-listen 4.0.0
remote:        Installing sass-listen 4.0.0
remote:        Fetching globalid 0.4.1
remote:        Installing globalid 0.4.1
remote:        Fetching activemodel 5.1.6
remote:        Installing activemodel 5.1.6
remote:        Fetching jbuilder 2.7.0
remote:        Installing jbuilder 2.7.0
remote:        Fetching sass 3.7.2
remote:        Installing sass 3.7.2
remote:        Fetching activejob 5.1.6
remote:        Installing activejob 5.1.6
remote:        Fetching activerecord 5.1.6
remote:        Installing activerecord 5.1.6
remote:        Fetching rails-dom-testing 2.0.3
remote:        Fetching loofah 2.2.3
remote:        Installing rails-dom-testing 2.0.3
remote:        Installing loofah 2.2.3
remote:        Fetching rails-html-sanitizer 1.0.4
remote:        Installing rails-html-sanitizer 1.0.4
remote:        Fetching actionview 5.1.6
remote:        Installing actionview 5.1.6
remote:        Fetching actionpack 5.1.6
remote:        Installing actionpack 5.1.6
remote:        Fetching actionmailer 5.1.6
remote:        Fetching railties 5.1.6
remote:        Fetching actioncable 5.1.6
remote:        Installing actionmailer 5.1.6
remote:        Installing actioncable 5.1.6
remote:        Installing railties 5.1.6
remote:        Fetching sprockets-rails 3.2.1
remote:        Installing sprockets-rails 3.2.1
remote:        Fetching jquery-rails 4.3.1
remote:        Fetching rails 5.1.6
remote:        Fetching coffee-rails 4.2.2
remote:        Installing rails 5.1.6
remote:        Installing coffee-rails 4.2.2
remote:        Fetching sass-rails 5.0.6
remote:        Installing sass-rails 5.0.6
remote:        Installing jquery-rails 4.3.1
remote:        Bundle complete! 15 Gemfile dependencies, 57 gems now installed.
remote:        Gems in the groups development and test were not installed.
remote:        Bundled gems are installed into ./vendor/bundle.
remote:        Post-install message from sass:
remote:        
remote:        Ruby Sass is deprecated and will be unmaintained as of 26 March 2019.
remote:        
remote:        * If you use Sass as a command-line tool, we recommend using Dart Sass, the new
remote:          primary implementation: https://sass-lang.com/install
remote:        
remote:        * If you use Sass as a plug-in for a Ruby web framework, we recommend using the
remote:          sassc gem: https://github.com/sass/sassc-ruby#readme
remote:        
remote:        * For more details, please refer to the Sass blog:
remote:          http://sass.logdown.com/posts/7081811
remote:        
remote:        Bundle completed (43.69s)
remote:        Cleaning up the bundler cache.
remote: -----> Installing node-v8.10.0-linux-x64
remote: -----> Detecting rake tasks
remote: -----> Preparing app for Rails asset pipeline
remote:        Running: rake assets:precompile
remote:        Yarn executable was not detected in the system.
remote:        Download Yarn at https://yarnpkg.com/en/docs/install
remote:        I, [2018-11-21T07:21:47.419386 #1376]  INFO -- : Writing /tmp/build_a47d32405f236aed0cca858ff64dcf0e/public/assets/application-7e084e44b9a13db0cda25bad2ac6fdbbfe31462ec93176e245cd0bcbc079f436.js
remote:        I, [2018-11-21T07:21:47.420053 #1376]  INFO -- : Writing /tmp/build_a47d32405f236aed0cca858ff64dcf0e/public/assets/application-7e084e44b9a13db0cda25bad2ac6fdbbfe31462ec93176e245cd0bcbc079f436.js.gz
remote:        I, [2018-11-21T07:21:47.425870 #1376]  INFO -- : Writing /tmp/build_a47d32405f236aed0cca858ff64dcf0e/public/assets/application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css
remote:        I, [2018-11-21T07:21:47.426144 #1376]  INFO -- : Writing /tmp/build_a47d32405f236aed0cca858ff64dcf0e/public/assets/application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css.gz
remote:        Asset precompilation completed (2.70s)
remote:        Cleaning assets
remote:        Running: rake assets:clean
remote: -----> Detecting rails configuration
remote: 
remote: ###### WARNING:
remote: 
remote:        You have not declared a Ruby version in your Gemfile.
remote:        To set your Ruby version add this line to your Gemfile:
remote:        ruby '2.4.5'
remote:        # See https://devcenter.heroku.com/articles/ruby-versions for more information.
remote: 
remote: ###### WARNING:
remote: 
remote:        Detecting rails configuration failed
remote:        set HEROKU_DEBUG_RAILS_RUNNER=1 to debug
remote: 
remote: ###### WARNING:
remote: 
remote:        No Procfile detected, using the default web server.
remote:        We recommend explicitly declaring how to boot your server process via a Procfile.
remote:        https://devcenter.heroku.com/articles/ruby-default-web-server
remote: 
remote: 
remote: -----> Discovering process types
remote:        Procfile declares types     -> (none)
remote:        Default types for buildpack -> console, rake, web
remote: 
remote: -----> Compressing...
remote:        Done: 41.1M
remote: -----> Launching...
remote:        Released v6
remote:        https://sleepy-tundra-20972.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/sleepy-tundra-20972.git
 * [new branch]      master -> master

おー、今度はエラーにならなかった。よしよし。つか、ここまでは1章と何も変わらない。

さて、scaffoldはデータモデルからえいやっとする方法なので、データモデルを作る。10年前にRailsをちょっとだけ勉強したときには普通にCREATE TABLEしてそこから作ってた気がするけど、もうそういう時代ではないらしい。

> bundle exec rails generate scaffold User name:string email:string
      invoke  active_record
      create    db/migrate/20181121083708_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      create      app/views/users/_user.json.jbuilder
      invoke  test_unit
      create    test/system/users_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss
> bundle exec rails db:migrate
== 20181121083708 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0009s
== 20181121083708 CreateUsers: migrated (0.0010s) =============================

作る順番が逆転してるわー。

rails newしてからDBの設定なんかしていないわけだけども、デフォルトがSQLiteになっているようだ。config/database.ymlをみるとそう書いてある。で、DBが作られた訳ね、どこかに。というか、database.ymlによれば、db/development.sqlite3ですな。

> ls db
development.sqlite3 migrate             schema.rb           seeds.rb

さて、この段階でrails serverしてscaffoldで出来たUserの画面を見てみよう。

> bundle exec rails server
=> Booting Puma
=> Rails 5.1.6 application starting in development 
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.9.1 (ruby 2.5.1-p57), codename: Private Caller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

これでUSERテーブルのCRUDの機能に/usersでアクセスできる。お馴染みのscaffoldだ。Railsの原点とも言える。

Railsは「Webアプリなんて所詮、ドメインモデルをそのままテーブル構造に反映させたDBへのCRUD機能でほとんどまかなえるんだ」と言い放った。もちろん、そんな簡単なアプリばかりではないけども、簡単なアプリ(それこそブログとか)ならそれで作れて、それを最速で作れるように特化したのがRailsであり、その際に使われたのがRubyメタプログラミング(=黒魔術)だったというのが、Ruby on Railsの成り立ちである。そこから思えば遠くにきたものだ。

感慨にふけっていても仕方が無いので、どんどんいこう。

その前に2.2.1の演習だ。

1つ目は、ユーザー作成時のメッセージを調べてみろとのことだ。

f:id:Tambourine:20181121212056p:plain

こうなってる。

リロードすると、<p id="notice">の中身は消える。

app/views/users/show.html.erbを見ると、

<p id="notice"><%= notice %></p>

となっている。

app/controllers/users_controller.rbを見ると、

  # POST /users
  # POST /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

こうなっているので、メッセージの元はここだ。

リロードすると呼び出されるのは

  # GET /users/1
  # GET /users/1.json
  def show
  end

こっちなので、何にも出ないのだと思われる。というか、空のメソッド定義を作ると何が起きるの?

さて、2つ目。名前だけで、emailを入力しないとどうなるか。普通に作られる。 テーブル定義を確認してみよう。

> sqlite3 development.sqlite3 
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .table
ar_internal_metadata  schema_migrations     users               
sqlite> .schema users
CREATE TABLE IF NOT EXISTS "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "email" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);

NOT NULLじゃないのでNULLが入るのか・・・と思いきや、単に長さ0の文字列は入っているっぽい。

sqlite> SELECT name, '>' || email || '<' FROM users;
太郎冠者|>taro@ex.com<
次郎冠者|>jiro@ex.com<
三郎|><

まあ、自然だ。演習3も、別に普通に入る。validationはまだ何にもしていないんだし。

sqlite> sqlite> SELECT name, '>' || email || '<' FROM users;
太郎冠者|>taro@ex.com<
次郎冠者|>jiro@ex.com<
三郎|><
士郎正宗|>@example.com<

演習4。削除の挙動を確認する。削除は、ダイアログが出る。 どうなっているかというと、削除のリンクはこう定義されてる。

<a data-confirm="Are you sure?" rel="nofollow" data-method="delete" href="/users/3">Destroy</a>

よくわからない・・・。

ググるとこういうことらしい。

[コードリーディング] link_toの:methodと:confirmの挙動 - Qiita

な、なるほど・・・javascriptとrackの合わせ技でDELETEメソッドHTMLから送れるようにしているってことか・・・。すごいね。

2.2.2は仕組みの説明。読んで、演習に行ってみる。

演習は、/users/1/editの振る舞いの説明。編集はupdateアクション。updateはPATCHメソッドに紐づいている。 PATCHって初めて聞いた。PUTじゃないのか・・・。

/users/1/editに行くと、こんなHTMLが表示される。

<form action="/users/3" accept-charset="UTF-8" method="post">
  <input name="utf8" value="✓" type="hidden">
  <input name="_method" value="patch" type="hidden">
  <input name="authenticity_token" 
    value="5QWnf/p1Bjq4xi/HM12xu0gzsvS40Q9VjImgUP4sCDCrK9xq/fRn5vO1/VpT4UR167Ac858VSlZlWU6lX6KQ5Q==" 
    type="hidden">

  <div class="field">
    <label for="user_name">Name</label>
    <input id="user_name" value="三郎" name="user[name]" type="text">
  </div>

  <div class="field">
    <label for="user_email">Email</label>
    <input id="user_email" value="" name="user[email]" type="text">
  </div>

  <div class="actions">
    <input name="commit" value="Update User" data-disable-with="Update User" type="submit">
  </div>
</form>

_method=patchを送ることにより、PATCHメソッドに変換されるようにhiddenがセットされてる。ふむふむ。

これの元になったviewはこんなerbだ。app/views/users/edit.html.erb。

<h1>Editing User</h1>

<%= render 'form', user: @user %>

<%= link_to 'Show', @user %> |
<%= link_to 'Back', users_path %>

えええ、まじでーって感じ。上の<form>は1行かー・・・。

さて、演習の2はUPDATE文を投げている部分はどこか探してみようの巻。updateメソッドを見れば良いはず。

  # PATCH/PUT /users/1
  # PATCH/PUT /users/1.json
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

あー、PUTでもいいらしい。UPDATEをやっているのは@user.update(user_params)だろう。 でも、user_paramsって何だろう。あ、privateなメソッドがある。

    # Never trust parameters from the scary internet, only allow the white list through.
    def user_params
      params.require(:user).permit(:name, :email)
    end

セキュリティ的にちゃばいかもよというコメントがついている。親切だ。 しかし、このメソッドを見ても何にもわからないな・・・。 まあ、おそらくparamsはリクエストのパラメータすべてで、そこからuser[:name]とuser[:email]だけを 選んだものを返すということなんだろう。たぶん。

3は上でもう答えたので完了。

2.2.3はさらっと読んで終わり。validationとtestとdesignがなく、意味もわからないから困るねと書いてある。 「scaffoldのコードを理解できるぐらいなら、そもそも本書を読む必要はないでしょう」ごもっとも。