kikeda1104's blog

備忘録・技術に関することを書いています。(webエンジニア)

PostgreSQLサーバの起動コマンド

毎回ググっているので、自分の備忘録として残しています。

環境

## PostgreSQLサーバの起動(homebrewでインストール)
postgres -D /usr/local/var/postgres

参考

18.3. データベースサーバの起動

drop_tableの代わりにActiveRecordMigration#revert

環境

前提

初期からRailsでアプリを作成していて、tableを作成したmigrationもそのアプリが保有していることが前提になります。

modelを途中で消す場合、./bin/rails d model model_nameで消すと作成した際、migration fileも削除される。 途中で、カラムを追加・変更・削除している場合は、./bin/rails db:migrateが失敗することになり、modelを削除する際には、気をつけないと、migrateを一から実行することができなくなり、復旧することになります。

revert

rails app単体の構成であれば、drop_tableを使ってテーブルを削除するよりも、revertを使うのが良いと思います。 では、手順ですが、一度作成したmodel、testファイル、該当するコードを削除した後、tableを作成したmigrationは残しておき、新規drop用のmigration fileを準備します。

サンプル

model bread作成

f:id:kikeda1104:20170630224831p:plain

model rice作成

f:id:kikeda1104:20170630232206p:plain

migrate実行とgit commit

./bin/rails db:migrate
git add . && git commit -m "add bread and rice models"

model bread削除

./bin/rails d model bread
git checkout db/migrate
./bin/rails g migration DropBreadsTable

作成したmigrationをエディタで開く

require_relative '20170629123105_create_breads' # 追記(migrationファイル名は、適切なファイル名に直してください)

class DropBreadsTable < ActiveRecord::Migration[5.1]
  def change
    revert CreateBreads # 追記 create_breadsをキャメルケースに直してrevertの引数に渡す。
  end
end

以上です。これで、migrate, rollbackすることができます。

別サンプル

途中で、カラムを追加していた場合のケースも追加しておきます。

breadsにcolumnを追加

./bin/rails g migration AddIsSweetnessToBreads

migration file編集

class AddIsSweetnessToBreads < ActiveRecord::Migration[5.1]
  def change
    add_column :breads, :is_sweetness, :boolean, default: false
  end
end

テーブルを削除するmigration fileを作成

require_relative '20170630135043_add_is_sweetness_to_breads'
require_relative '20170630134600_create_breads'

class DropBreadsTable < ActiveRecord::Migration[5.1]
  def change
    revert AddIsSweetnessToBreads
    revert CreateBreads
  end
end

以上です。

./bin/rails db:migrate
./bin/rails db:rollback STEP=3
./bin/rails db:migrate

複数テーブルの操作をmigrationに書き込んでいる場合

このケースだと対応はできないです。 migration fileは、1テーブルの操作に制限して、プロジェクトメンバーに周知して守らせる必要がありそうです。 (上記をオススメしますが、migration fileの書き方で、dropしないテーブルに関する操作をrevert後にコピーしてくることで復旧できそうなので、 今度改めて、追記します。)

参考

http://api.rubyonrails.org/classes/ActiveRecord/Migration.html#method-i-revert

https://railsguides.jp/active_record_migrations.html#%E4%BB%A5%E5%89%8D%E3%81%AE%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E9%80%86%E8%BB%A2%E3%81%99%E3%82%8B

Capybara aタグ(target="_blank")をクリックについて

掲題の件、featureテストを書く量が日に日に増えてきており、何を書くかと書き足りないケースなどを自覚できるになり知見も日々、蓄積できていて楽しく、 クライアントと紹介してくれた友人に感謝っすね。

aタグのtarget属性(_blank)

新規ウィンドウ、タブを開いてページを表示した後、表示したページで、タイトルを確認する方法を書いていきます。

環境

サンプルコード

require 'rails_helper'

feature 'TOP画面からの操作', type: :feature do
  scenario 'ユーザがリンクをクリックして新規タブが開いている' do
    within_window(window_opened_by { first("a.new-window-link").click }) do
      expect(page).to have_content '新しいページタイトル'
    end
   end
 end

#  なお、within_window(string)は、非推奨になっているため注意。

感想

テストを書いているプロジェクトって、本当少ないですよね・・。

参考

Method: Capybara::Session#within_window — Documentation for capybara (2.14.3)

Rails 5.0からRails 5.1へのアップデート(1/?)

こんにちは。時間の合間に作成しているサービスのRailsを5.0から5.1へアップデートしていまして その内容を書いています。rails upgrade guideが、まだ作成中で、issueを読んで対応していました。

テスト, jsの移行は、まだ終わっていなくて順次移行中です。

環境

Gemfile

Gemのversionをあげます。(環境によって異なります)

# Gemfile
gem 'rails', '5.1.0' # Use sqlite3 as the database for Active Record
gem 'puma', '~> 3.7'
gem 'webpacker'
gem 'coffee-rails', '~> 4.2'
  
group :development, :test do
 # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '~> 2.13.0'
  gem 'selenium-webdriver'
end

group :development do
  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

参考: https://github.com/kikeda1104/9syoku/blob/master/Gemfile

bundle install or bundle update

./bin/rails app:update

rails 5.0でも使われていた、binファイルや設定ファイルを更新してくれる./bin/rails app:updateがありますのでこれを利用します。 config、routeが上書きされるので、差分をとって編集しましょう。

./bin/rails app:update

secret.ymlの暗号化

./bin/rails secrets:setup

f:id:kikeda1104:20170504161357p:plain

secrets.yml.keyが作成され、gitignoreに追加されます。 secrets.yml.encを編集したい場合は、`./bin/rails secrets:edit'です。

f:id:kikeda1104:20170504161633p:plain 上のメッセージが出たら、EDITOR=vi bin/rails secrets:edit EDITORは、好みで変えてください。

productionのsecret_key_baseをこちらに設定して保存します。

webpacker

これは、新規だった場合に、rails new rail_app --webpack –webpackオプションを指定すると、自動でwebpacker gemがGemfile bundle installによりgemがインストールされます。

./bin/rails -T 一部省略

f:id:kikeda1104:20170504162456p:plain

namespaceにwebpackerとついているのは、webpacker gemが導入されることにより追加されるタスクです。 vueを含めてみます。

./bin/rails webpacker:install:vue

f:id:kikeda1104:20170504163358p:plain

migrationファイル

ActiveRecord::Migration => ActiveRecord::Migration[5.0 or 5.1]に修正

./bin/rails db:drop RAILS_ENV=production && ./bin/rails db:create RAILS_ENV=production && ./bin/rails db:migrate RAILS_ENV=production

RAILS_ENV=production ./bin/rails assets:precompile

puma起動

RAILS_ENV=production ./bin/rails s

まとめ

気が向いたら、細かい改善点を更新していきます。

近況

前職の会社を辞めてから、フリーランス(個人事業主)として働き始めて コードを書く機会が増えてきたので、知見を少しずつブログに書きためようかと思います。 友人の紹介による仕事ですが、色々と新しい経験を積める環境にあって感謝しています。

参考

A Guide for Upgrading Ruby on Rails — Ruby on Rails Guides

rails/5_1_release_notes.md at 39a2e1465e15d1da56ba1f4ed14fd38740bd86d4 · rails/rails · GitHub

circle.ymlの設定(bunlderのみ)

github上で、ソースを管理しており、プロジェクトでCIを利用しているが、Circle CIbunlderversionlocalと一致しない(lockfile)ことで、warningのメッセージが上がっていたので、circle.ymlを作成しました。

circle.yml

rootディレクトリに、circle.ymlを追加する。

# circle.yml
machine:
  ruby:
    version:
      2.3.3
  
dependencies:
  pre:
    - gem install bundler --pre

まずは、最小限の設定のみです。

参考

Sample circle.yml file - CircleCI

FormObject実装(2回目)

前回からの引き続き。viewとcontrollerの実装を進めていきます。

前回まで

FormObject実装(1回目) - kikeda1104's blog

controllerの実装

# controller/sample_forms_controller.rb

class SampleFormsController < ApplicationController
  def new
    @offer_form = OfferForm.new
  end
  
  def create
    @offer_form = OfferForm.new(job_offer_form_params)

    if @offer_form.save
      redirect_to :create, notice: '保存に成功しました'
    else
      render :new
    end
  end

  private
  
  def job_offer_form_params
    params.require(:job_offer_form).permit(JobOfferForm.attributes.keys)
  end
end

viewsの実装

続いて、viewsのフォームを作成します。

# views/sample_forms/new.html.haml
# ... 省略 : bootstrap利用しています。cssの定義については省略します

- form_for(@offer_form, polymorpic_path(@offer_form.job_offer)) do |f|
  # polymorpic_path([:admin, @offer_form.job_offer])も可能
  %fieldset
    %legend フォーム
    .form-group
      = f.label :title, class: 'col-md-2 control-label'
        col-md-10
        = f.text_field :title, placeholder: '例: ', class: 'form-control'
    .form-group
      = f.label :description, class: 'col-md-2 control-lable'
      .col-md-10
        = f.text_area :description, class: 'form-control'

    .form-acitons
      .row
        .col-md-12
          %button.btn.btn-default{ type: 'submit' }
            戻る
          %button.btn.btn-default{ type: 'submit' }
            %i.fa.fa-save
              確定    

ここまでです。次は、1回目の記事のサンプルコードを更新してから、form_objectsの実装をより進めていきます。

参考

http://blog.enogineer.com/2014/12/02/rails-form-object/

ActionDispatch::Routing::PolymorphicRoutes

FormObject実装(1回目)

form_objectの実装を進める際に、gem virtusを使って実装を進めたので、何度かに分けて書いていきます。

環境

gemの導入

Gemfileに追加します。

  # Gemfile
  ...
  gem 'virtus'
  ...

$ bundle install

app/forms

app/formsディレクトリを作成します。

  mkdir app/forms

config/initialze/forms.rbを作成して,下記を追加します。

# forms.rb
# require_dependecy 'parent_class'

Dir.glob('app/forms/**/*.rb') do |f|
  require_dependency(Rails.roots.join(f))
end

formクラス作成します。

## vim app/forms/offer_form.rb
class OfferForm
  include Virtus.model
  include ActiveModel::Model

  attr_accessor :errors
  attribute :id, Integer
  attribute :title, String
  attribute :description, String
  attribute :main_image, String
  attribute :side_image_left, String
  attribute :side_image_right, String
  attribute :status, Integer, default: 0
  attribute :type_of_job_id, Integer
  attribute :company_id, Integer
  attribute :adoption_of_shape_id, Integer
  attribute :confirming, Boolean, default: false
  attribute :type_of_job_id, Integer
  attribute job_of_offer, JobOffer

  validates :title, :status, :type_of_job_id, :adoption_of_shape_id, presence: true

  def persisted?
    job_offer.persisted?
  end
  ...
end

virtusREADMEに記載されていて、1:多の関係にある構造も実現できますので、accepts_nested_attributesを利用せずに 実装をこちらに変更することができます。

余談ですが、Optimistic lockingを実装する上で、accepts_nested_attributesでは、実現できない(仕様が通れば...)ケースがあり formObjectを通して、lock_versionをコントロールする設計を実現するのに、virtusを採用(しようとした)経緯がありました。

補足: 誤解を与えそうな表現になっていたので、訂正。virtusは、属性の型、タイプキャスト、初期値を実現します。 virtusを使わずに、form objectを作成することもできます。

今回は、ここまでです。

参考

GitHub - solnic/virtus: Attributes on Steroids for Plain Old Ruby Objects

肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)

Rails4でFormオブジェクトを作る際に気をつける3つのポイント|江の島エンジニアBlog

Railsで導入してよかったデザインパターンと各クラスの役割について - masato_hiのブログ

ActiveRecord::Locking::Optimistic

postgre sql サーバの起動方法(Cent7.x)

自宅のrailsアプリでは、posgreを使っていてサービス起動/停止する際にコマンドを忘れないためのメモです。

環境

起動方法

インストール方法により、サービス名も変わります。

# systemctl start postgresql

株式会社リューノスを退職しました。

SNSに投稿するには長文になっていたので、 重複しますが報告と退職の理由について書いていきます。

正確には記事の投稿している日は、まだ在籍中で、1月10日で退職します。

報告

最終日なのに15時位まで、コードを書き、マージまでして、17時過ぎても質問され続けていて疲れもしましたが、まあ、最終日も貢献することができ嬉しく思っています。

挨拶の後には、お花とプレゼントまで頂いて、退職することを感じつつ、嬉しい一日になりました。 (帰り際に牛乳をこぼすという不手際がなければ。。)

今の会社では、2年間、在籍することになり、在籍中に若手の教育と開発全般で、活躍できたと自負しています。関係者の皆さまありがとうございました。

今後は、フリーで働きながら、エンジニアのキャリアを積んでいきます。

退職ついて

実は退職の理由に、後ろめたい理由があるんじゃないかと疑われる方がいました。その方は、心配してくれて聞いてくれたんだと思っています(優しい方なので)

上司に退職の意思を伝える際に、きみは影響力があるからと言われて (正直そんな自覚はなかったのですが) 開発メンバーに対して積極的は発言や行動(もくもく会、プライベートのイベント)は控えていました。 できるだけ、まわりや若手の意見を優先して採用して欲しかったですし、そうすることで 退職するインパクトが下がると思っていたからです。

上に書いた事をやっていることと、社内で親しい方々に、私からでなく、所属している部長から退職1ヶ月前に私が退職する旨を発表する形になってしまったことが原因だと思っています。 私からはまだ言わないで欲しいと言われていることもあり、そちらを優先していましたが。別の方から退職を伝えるのではなく、私から直接伝えておけば、印象が違ったなと反省しています。

実際に退職理由はこれですと一言で言えなくなっていまして。 上司に退職する際に伝えた言葉は、マネジメントと開発を両立するのは、難しいので、開発に専念したい旨を伝えていました。それだけではなく、お金の面、経験の面、時間の面で より自分にとってより良い環境や条件で働きたいと願望があり、そちらを優先した次第です。

エンジニアとして、まだまだ技術力も知識を伸ばしていきたいです。 承認欲求も強くあります。若手の教育係としての仕事もしていましたが、若手の成長を優先してばかりいれるほど大人でもなかったので 自分にとって成長できる幅が大きい、自分にとって好条件かつ効率の良い生き方を優先したいというのが今回の退職理由です。

以上です。だらだら書きましたが、改めて関係者の方々、暖く見送っていただきありがとうございました。

仕事のご依頼は下記のメールアドレスにお願いいたします。

gankai1104@gmail.com

ActiveRecord::Base.establishによる複数回切り替え時の不具合

掲題の件、テスト書いていることで発見できまして、APIリファレンスを読むと割と合点はいきましたが 間違えなどあれば、指摘いただきたいです。

環境 - rails 5.0.0.1(puma) - ruby 2.3.1

ActiveRecord::Base.establishを何度も読み出すことで、queryを発行した際に事前に切り替えたDBではなく 切り替え前のDBのままqueryを実行する不具合がテストで見つかりましてその改善策です。

def change_schema
  ApplicationRecord.remove_connection
  ActiveRecord::Base.establish YAML.load_file(Rails.root.join('config', 'database.yml')[Rails.env]
end

clear_all_connection!などを実行しても、上手くリセットされていなかったので、remove_connectionからconnectiondisconnectで切断してから 動作するようになりました。

テストは恩恵も大きいし、テストを定常的に書くのも重要ですね。

参考

ActiveRecord::ConnectionAdapters::ConnectionHandler

https://github.com/rails/rails/blob/473473d7f73a43b8d1e4e604327998c5250dff3c/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L891