Diary/2022-10-2
Ruby on Rails はじめました
Getting Started with Railsを.ホストOSはUbuntu 20.04.
- 準備
RubyとSQLite3が必要,ということで,
$ sudo apt install ruby-full $ sudo apt install sqlite3-doc $ sudo apt install ruby-bundler
でずばっと.bundleはあれこれ必要になるのでいれとく.
$ ruby --version ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux-gnu] $ sqlite3 --version 3.31.1 2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837balt1
が入った.で,gemで rails をインストール.
$ sudo gem install
- やってみる
ガイド通りに
rails new blog
blog/ 以下にあれこれできている.
cd blog ./bin/rails server
でなんか起動した.
- Unicorn/Nginx経由でアクセスできるようにする
【Rails】Webサーバー「Unicorn」の基本情報と実装方法を参考に
Gemfileに
gem "unicorm"
を追加.PIDとソケット,ログの格納用ディレクトリを作る.
mkdir -p tmp/pids tmp/sockets log
で,設定ファイルconfig/unicorn.rbを丸っと作成.
# Railsアプリのルート rails_root = File.expand_path('../../', __FILE__) # Gemfileの場所 ENV['BUNDLE_GEMFILE'] = rails_root + "/Gemfile" # Unicornの設定 worker_processes 2 timeout 15 working_directory rails_root pid File.expand_path 'tmp/pids/unicorn.pid', rails_root listen File.expand_path 'tmp/sockets/.unicorn.sock', rails_root stdout_path File.expand_path 'log/unicorn.log', rails_root stderr_path File.expand_path 'log/unicorn.log', rails_root preload_app true # フォークが行われる前の処理 before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin Process.kill "QUIT", File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end # フォークが行われた後の処理 after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end # フォークが行われる前の処理 before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! end # フォークが行われた後の処理 after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end # フォークが行われる前の処理 before_fork do |server, worker| old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin Process.kill "QUIT", File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end
これで,
$ bundle exec unicorn -c config/unicorn.rb
とすると tmp/pids/unicorn.pid が作成されてPIDが格納されて,終了時に削除される.
Nginx側にエントリを追加するために site-available/hoge を編集.
Nginxからunicornにアクセスできるようにアップストリームの定義を追加して,
upstream unicorn { server unix://home/miyo/blog/tmp/sockets/.unicorn.sock; }
/ へのアクセスを定義したアップストリームに振れるように
location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://unicorn; }
とか.で,
sudo nginx -t sudo systemctl restart nginx.service
で再起動.あとは,
bundle exec unicorn -c config/unicorn.rb
でUnicorn起動した後でブラウザから,アクセスする.
うまくNginx→unicornの設定ができていれば,
Blocked host: ホスト名って感じのエラーがでる.
調べてみると,DNSリバインディング攻撃を防ぐため,らしい.
config.hosts << "ホスト名"
を追加せよ,とあるので,config/environments/development.rb の
Rails.application.configure do ... end
の末尾に,
config.hosts << "ホスト名"
を追加.あらためて
bundle exec unicorn -c config/unicorn.rb
で起動してブラウザからアクセスすると,なんかそれっぽいページが表示される.
- Say Hello
MVCのVとCを作ってHello Worldしよう,という内容.
config/routes.rbを変更
Rails.application.routes.draw do # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Defines the root path route ("/") root "articles#index" get "/articles", to: "articles#index" end
で,
bin/rails generate controller Articles index --skip-routes
としてcontrollerとviewを生成.
- app/controllers/articles_controller.rb
- app/views/articles/index.html.erb
- test/controllers/articles_controller_test.rb
- app/helpers/articles_helper.rb
が生成された.
app/views/articles/index.html.erb の 中身をガイドに従って編集して,
https://どこか/articles/ にアクセスしたら,index.html.erb の表示がみえた.
config/routes.rbをもう一度変更して,
Rails.application.routes.draw do root "articles#index" get "/articles", to: "articles#index" end
としたら,https://どこか/ にアクセスして作成したindex.html.erb の表示がみえた.
- Modelも作る
ガイド通りコマンドを実行してみる.
bin/rails generate model Article title:string body:text
ファイルが生成された.
- db/migrate/20221002090126_create_articles.rb
- app/models/article.rb
- test/models/article_test.rb
- test/fixtures/articles.yml
Articleっていう名前で,string型のtitleとbodyをもったモデルを作る,ということのよう.
db/migrate/20221002090126_create_articles.rbをみるとDBを作るcreate_tableが定義されている
で
bin/rails db:migrate
を実行.
bin/rails console
でirb使ってDBをいじる...ようだ.とりあえず言われるがままにやってみる.
article = Article.new(title: "Hello Rails", body: "I am on Rails!") article.save
Article.find(1)とかArticle.allとかするとエントリをひける.
裏では,
SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
とかってSQLが走っているようだ.
CとVを変更してブラウザからのアクセスで利用できるようにする.
app/controllers/articles_controller.rb を
class ArticlesController < ApplicationController def index @articles = Article.all end end
と編集し,app/views/articles/index.html.erb を
<h1>Articles</h1> <ul> <% @articles.each do |article| %> <li> <%= article.title %> </li> <% end %> </ul>
にする.erbの @articlesは,controller.rbの @articlesに対応している.
Rubyの return value が欲しくないときは <% %> を,欲しいときには <%= %>を使うらしい.
- CRUDのReadを試す
routeを追加する.config/routes.rb をアップデート
Rails.application.routes.draw do root "articles#index" get "/articles", to: "articles#index" get "/articles/:id", to: "articles#show" end
:id はrouteのパラメタ.
で,app/controllers/articls_controller.rbにコントローラを追加.
routeに追加した show と :id がどう使われるか見てとれる.
def show @article = Article.find(params[:id]) end
また,app/views/articles/show.html.erbを作成
<h1><%= @article.title %></h1> <p><%= @article.body %></p>
Webブラウザで / にアクセスするとテーブルに登録された一覧とshowへのリンクが.
で,リンク先の /articles/1 などにアクセスすると,showの定義通りtitleとbodyが.
- CRUD関連の便利な記法
CRUD関連のrouteをひとつひとつ定義するかわりに resources が使えるらしい.
config/routes.rb をアップデート
Rails.application.routes.draw do root "articles#index" resources :articles end
bin/rails routesで確認すると,articlesに関連して,あれこれ定義されているのがわかる.
root GET / articles#index articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy
index.html.erbもaタグを自分で書くんじゃなくて,簡略化できる
<h1>Articles</h1> <ul> <% @articles.each do |article| %> <li> <%= link_to article.title, article %> </li> <% end %> </ul>
- CRUDのCreate
サンプルまま作業.ただ,そのままだと,
ActionController::InvalidAuthenticityToken (HTTP Origin header (https://****) didn't match request.base_url (http://****)):
なエラーがでてPOSTがはじかれていた.
これはRails側ではなくて,Nginxでhttpsをほどているのが問題.
というわけで,site-available/hoge の location / {...} に,
proxy_set_header origin 'http://****';
を追加.
hoge.html.erbで,他の.html.erbファイルを読みこむことができる.
<%= render "form", article: @article %>
とかすると,_form.html.erbと,先頭に'_'が付いたファイルが読み込まれる,ようだ.