edo1z blog

プログラミングなどに関するブログです

Rails - 色々やってみる

$ rails new rails1
$ cd rails1
$ rails db:migrate

プロジェクト作っていきなりdb:migrateしたら、developement.sqlite3と、schema.rbが作成された。中身はからなはず。DataGrip使って見てみる。空だ。 とりあえず1つscaffoldする。

$ rails g scaffold user name:string email:string
      invoke  active_record
      create    db/migrate/20170411151003_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  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

大量のものを作成している。 この状態で、rails sをすると下記エラーがでる。

Migrations are pending. To resolve this issue, run: bin/rails db:migrate RAILS_ENV=development

マイグレーションをDBに反映してないことが分かるようです。 マイグレーションファイルを見てみます。

class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

ではSQLiteを見てみます。DataGrip便利だな。usersテーブルができていて、created_at、updated_atもあります。idというプライマリーキーもあります。 scaffoldするとjsonにも対応している。

とりあえずViewにBootstrapを適用してみる。その前に、cssとかの読み込み状態を確認してみる。

<link rel="stylesheet" media="all" href="/assets/scaffolds.self-50415e02e26bd1d252d84df1b2baeea859ec7e1c4f26c45a801029454454bc62.css?body=1" data-turbolinks-track="reload" />
<link rel="stylesheet" media="all" href="/assets/users.self-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css?body=1" data-turbolinks-track="reload" />
<link rel="stylesheet" media="all" href="/assets/application.self-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css?body=1" data-turbolinks-track="reload" />
    <script src="/assets/jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/jquery_ujs.self-784a997f6726036b1993eb2217c9cb558e1cbb801c6da88105588c56f13b466a.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/turbolinks.self-c5acd7a204f5f25ce7a1d8a0e4d92e28d34c9e2df2c7371cd7af88e147e4ad82.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/action_cable.self-5454023407ffec0d29137c7110917e1e745525ae9afbc05f52104c4cd6597429.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/cable.self-6e0514260c1aa76eaf252412ce74e63f68819fd19bf740595f592c5ba4c36537.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/users.self-877aef30ae1b040ab8a3aba4e3e309a11d7f2612f44dde450b5c157aa5f95c05.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/application.self-b89234cf2659d7fedea75bca0b8d231ad7dfc2f3f57fcbaf5f44ed9dc384137b.js?body=1" data-turbolinks-track="reload"></script>

なんか激しい感じだ。cakephpと違ってAssetまで融合させようとしている感じがひしひしと伝わってくる。 app/assets/javascrptsとapp/assets/styleshetsの中にあるものが全部読み込まれている。

<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

この設定を変えると変わるはず。Jsはjquery,jquery-uiとかも勝手にインストールされている。外す方法確認しないと。

下記のようにやると、assetが結合・圧縮されるらしい。処理内容は設定によるだろうけど。

$ rails assets:precompile RAILS_ENV=production

app/assets/javascripts/application.jsと、app/assets/stylesheets/application.cssには、下記のような記述がありここを変更すると読み込む内容を変更できるらしい。

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

assetが便利だけど複雑だな。rails sをやり直さないとエラーのままになることあるな。

$ rails assets:precompile RAILS_ENV=production

をやったら、確かにpublic/assetsに圧縮されたものが格納された。 js/css共に1つのファイルが出力された。あとはgzファイルもある。このコンパイルをしておけば、本場環境ではこれらを読み込むようになるはず。

Railsのコード短いなー。scaffoldだとバリデーションないので、モデルのバリデーション入れてみる。

class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
            format: { with: VALID_EMAIL_REGEX },
            uniqueness: { case_sensitive: false }
end

入力画面で空状態で登録押すとエラーでる。cakephpみたいにformにまでvalidationが反映されるわけではないのかな。 英語のエラーだから日本語にしてみる。Djangoみたいに、設定ファイルで日本語ってやると日本語になるわけではないらしい。 やり方ここに書いてあった。

ja.ymlをconfig/locales/に追加 config/application.rbにconfig.i18n.default_locale = :jaを追加 サーバーを再起動 さらにモデルの属性名(nameなど)を日本語化する場合は、ja.ymlに次のように記載して下さい。 # config/locales/ja.yml ja: attributes: name: 名前 ...

3 error prohibited this user from being saved:というバリデーションエラーのメッセージは英語のままだな。

new.html.erbがすごい。3行しかない。でもrenderだからパーシャルを読み込んでるわけで、全自動でフォームが作られてるわけではない。

<h1>New User</h1>

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

<%= link_to 'Back', users_path %>

パーシャルは、下記のように書く。これは_form.html.erbを読み込む。アンダーバーがパーシャルのしるしらしい。

<%= render 'form'%>

パーシャルの内容は下記。

<%= form_for(user) do |f| %>
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>

  <div class="field">
    <%= f.label :email %>
    <%= f.text_field :email %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

エラーメッセージがベタ打ちだから英語のままだったんだな。

エラーメッセージの表示方法はアプリケーションごとに異なるため、Railsではこれらのメッセージを直接生成するビューヘルパーは含まれていません。 しかし、Railsでは一般的なバリデーションメソッドが多数提供されているので、カスタムのメソッドを作成するのは比較的簡単です。また、scaffoldを使用して生成を行なうと、そのモデルのエラーメッセージをすべて表示するERBがRailsによって一部の_form.html.erbファイルに追加されます

bootstrapに対応して、エラーを日本語にしてみた。

<div class="row">
<%= form_for(user) do |f| %>
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= user.errors.count %>件のエラーが発生しました</h2>
      <ul>
      <% user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <div class="col-md-6">
    <%= form_for(@user, url: users_path) do |f| %>
        <div class="form-group">
          <%= f.label :name %>
          <%= f.text_field :name, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :email %>
          <%= f.email_field :email, class: 'form-control' %>
        </div>
        <%= f.submit "submit", class: "btn btn-primary" %>
    <% end %>
  </div>
<% end %>
</div>

エラー発生フィールドはエラークラスのdivで囲われるから、それにスタイルつければ、エラーここだよ、というのが示せる。

次は、モデル(アクティブレコードと呼ぶらしい)のクエリ系のやつ覚えて、セッション、キャッシュとか確認して、認証のやり方確認して、セキュリティに関して確認したら大体何でもできそう。