そんなにrails newする機会なんてないでしょと思ってたら意外にあるのでメモっとく。

docker-composeで動くようにする

ざっとした手順はここ。

Quickstart: Compose and Rails | Docker Documentation

なんか僕はこんな感じの起動ファイルを使うようにしてる(なんでだか忘れた)。

上述の手順ではbundle installがイメージに突っ込まれるので、Gemfileを変えたけどbuildめんどいとりあえず動かしたい!ってときのためか・・・?

  web:
    command: bin/docker-bootstrap

中身はこう。

#!/bin/bash

bundle check || bundle install
bundle exec rake db:migrate
bundle exec rails s -p 3001 -b '0.0.0.0'

docker-compose.ymlはだいたいこんな感じになることが多い。

version: '2'

services:
  db:
    image: postgres:alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
  es:
    build:
      context: .
      dockerfile: ./elasticsearch/Dockerfile
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
  # kibana:
  #   image: kibana:5
  #   environment:
  #     - ELASTICSEARCH_URL=http://es:9200
  #   ports:
  #     - "5601:5601"
  web:
    build: .
    command: bin/docker-bootstrap
    volumes:
      - .:/myapp
    environment:
      - ELASTICSEARCH_URL=es:9200
    ports:
      - "3001:3001"
    depends_on:
      - db
      - es

volumes:
  pgdata:
    external: false
  esdata:
    external: false

kibanaは重い!

そういやver 3が出たとか出てないとか?

Gemfileを書く

まあこれはアプリによって違うけど毎回使ってるものもあってあれ忘れてた!みたいなのあるからまとめとこう。

なんか:development, :testのところあやしいな・・・?

group :development, :test do
  gem 'faker'
  gem 'rubocop', '~> 0.47.1'
  gem 'letter_opener'
  gem 'letter_opener_web'
  gem "rails_best_practices"
  gem 'scss_lint', require: false
end

group :test do
  gem 'database_cleaner'
end

gem 'config'
gem 'seed-fu', '~> 2.3'

gem 'kaminari'
gem "gretel"
gem 'activerecord-session_store'
gem 'activerecord-import'
gem 'bcrypt', '~> 3.1.7'

gem 'mailgun-ruby', '~>1.1.4'

gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'

gem 'pundit'
gem 'dotenv-rails', require: 'dotenv/rails-now'
gem 'carrierwave', '~> 1.0'
gem 'cloudinary'
gem 'meta-tags'

入れて終わりなGemばっかりじゃないのでそれらは以下にメモ。

rails_best_practices

なんかやりすぎなところをoffっただけな気がする。

rails_best_practices -g
AddModelVirtualAttributeCheck: { }
AlwaysAddDbIndexCheck: { }
#CheckSaveReturnValueCheck: { }
#CheckDestroyReturnValueCheck: { }
DefaultScopeIsEvilCheck: { }
DryBundlerInCapistranoCheck: { }
#HashSyntaxCheck: { }
IsolateSeedDataCheck: { }
KeepFindersOnTheirOwnModelCheck: { }
#LawOfDemeterCheck: { }
#LongLineCheck: { max_line_length: 80 }
MoveCodeIntoControllerCheck: { }
MoveCodeIntoHelperCheck: { array_count: 3 }
MoveCodeIntoModelCheck: { use_count: 2 }
MoveFinderToNamedScopeCheck: { }
MoveModelLogicIntoModelCheck: { use_count: 4 }
NeedlessDeepNestingCheck: { nested_count: 2 }
NotRescueExceptionCheck: { }
NotUseDefaultRouteCheck: { }
NotUseTimeAgoInWordsCheck: { }
OveruseRouteCustomizationsCheck: { customize_count: 3 }
ProtectMassAssignmentCheck: { }
RemoveEmptyHelpersCheck: { }
#RemoveTabCheck: { }
RemoveTrailingWhitespaceCheck: { }
#RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
#RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
#RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 }
ReplaceInstanceVariableWithLocalVariableCheck: { }
RestrictAutoGeneratedRoutesCheck: { }
SimplifyRenderInControllersCheck: { }
SimplifyRenderInViewsCheck: { }
#UseBeforeFilterCheck: { customize_count: 2 }
UseModelAssociationCheck: { }
UseMultipartAlternativeAsContentTypeOfEmailCheck: { }
#UseParenthesesInMethodDefCheck: { }
UseObserverCheck: { }
UseQueryAttributeCheck: { }
UseSayWithTimeInMigrationsCheck: { }
UseScopeAccessCheck: { }
UseTurboSprocketsRails3Check: { }

rubocop

めんどくせえ!ってやつはだいたいdisable。わるそなやつはだいたい友達。

AllCops:
  TargetRubyVersion: 2.4
  Exclude:
    - 'bin/**/*'
    - 'db/**/*'

Metrics/ClassLength:
  Enabled: false

Metrics/MethodLength:
  Enabled: false

Metrics/LineLength:
  Enabled: false

Metrics/ModuleLength:
  Enabled: false

Metrics/BlockLength:
  Enabled: false

Metrics/AbcSize:
  Enabled: false

Metrics/CyclomaticComplexity:
  Enabled: false

Style/StringLiterals:
  Enabled: false

Style/Documentation:
  Enabled: false

Style/WordArray:
  Enabled: false

Style/PercentLiteralDelimiters:
  Enabled: false

Style/MutableConstant:
  Enabled: false

Style/FrozenStringLiteralComment:
  Enabled: false

Style/TrailingCommaInArguments:
  Enabled: false

Style/TrailingCommaInLiteral:
  Enabled: false

Bundler/OrderedGems:
  Enabled: false

Style/Lambda:
  Enabled: false

scss-lint

smacssのやつだけあれば正直ほかは全部いらない!

scss_files: 'app/assets/stylesheets/**/*.scss'

linters:
  PropertySortOrder:
    order: smacss

  ColorVariable:
    enabled: false

  SelectorDepth:
    enabled: false

  NestingDepth:
    enabled: false

  Comment:
    enabled: false

  VendorPrefix:
    enabled: false

  StringQuotes:
    enabled: false

  QualifyingElement:
    enabled: false

  SingleLinePerSelector:
    enabled: false

  SingleLinePerProperty:
    enabled: false

  PlaceholderInExtend:
    enabled: false

  MergeableSelector:
    enabled: false

gretel

rails generate gretel:install

だいたいいつもこんなことしてるな。冗長な気してきた。

<% if (bc = breadcrumbs semantic: true, display_single_fragment: true).present? %>
  <nav class="breadcrumb">
    <div class="l-container">
      <%= bc %>
    </div>
  </nav>
<% end %>

railsconfig

rails g config:install

activerecord-session_store

個人のときは最初っからKVSとか使わないからね!

rails generate active_record:session_migration

config/initializers/session_store.rbに。

Rails.application.config.session_store :active_record_store, :key => '_my_app_session'

letter_opener_web

ヘッドレスな環境だとletter_openerが動かないからね!

config/routes.rbに。

config.action_mailer.delivery_method = :letter_opener_web

letter_opener

config/environments/development.rbに。

mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?

meta_tags

rails generate meta_tags:install

application_controllers.rbに。

before_action :set_default_meta_tags

def set_default_meta_tags
  set_meta_tags title: t('.title', default: :lead),
                canonical: canonical(locale: params[:locale]), # これもURLでi18nやるなら
                alternate: {
                  "x-default": canonical
                }

  # URLでi18nやるならね
  I18n.available_locales.each { |l| set_meta_tags alternate: { l => canonical(locale: l) } }
end

mailgun-ruby

config/environments/production.rbに。

config.action_mailer.delivery_method = :mailgun
config.action_mailer.mailgun_settings = {
  api_key: 'api-myapikey',
  domain: 'mydomain.com',
}

api_keydotenvとかでやるのがいいかな。動かしたことないからベストプラクティスがわからん!

pundit

rails g pundit:install

SCSSを作る

この辺は毎回違うこと書いてるし構造もそれぞれだな。

cd app/assets/stylesheets
mkdir modules
touch modules/_modules.scss
touch _layouts.scss
touch _helpers.scss
touch _resets.scss
touch _variables.scss

application.scssはこんな。

%clearfix {
  &::after {
    content: '';
    display: block;
    clear: both;
  }
}

@import "variables";
@import "helpers";
@import "resets";
@import "layouts";
@import "modules/*";

*.jbuilderを作らないようにする

config/generators.rbに。

これだとControllerのformatなんたらができちゃうけどそれはもう手で消してる・・・。 Gemfileからjbuilder消せばいいんだけど、使うかもだし・・・。

Rails.application.config.generators do |g|
  g.jbuilder false
end

application.html.erb

僕はhamlが好きじゃないのでいつもERB。

<head>
  <%= display_meta_tags site: t('title'), reverse: true, separator: "-" %>

  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
  <link rel="preload" href="https://fonts.googleapis.com/css?family=Ewert|Lato:400,700" as="style" onload="this.rel='stylesheet'">
  <link rel="preload" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" as="style" onload="this.rel='stylesheet'">
  <noscript>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ewert|Lato:400,700">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
  </noscript>
  <%= csrf_meta_tags %>

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

  <%= yield(:head) %>
</head>

Google Fontsとかはいらないならいらないな。

shared/_errors.html.erb

いつもformの直下に置くやつ。考えてみたらformの中である必要なんてなかった!

<% if object.errors.any? %>
  <div class="alert danger form">
    <ul>
      <% object.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>
<%= render "shared/errors", object: @user %>