- Product Manager
- Web Engineer
- Customer Support
- Other occupations (60)
- Development
-
Business
- Product Manager
- プロダクトマネージャー
- 広報
- カルチャー推進・浸透
- 知財戦略立案・推進・発明発掘
- リスクマネジメント統括本部
- 内部監査
- AML/CFTコンプライアンス
- AML・金融犯罪対策Ops
- 金融コンプライアンス
- システム監査
- ビジネス採用担当
- 経営企画(予実・IR)
- HRBP
- Legal
- 債権管理/MFK
- ToB Sales
- インサイドセールス
- フィールドセールス
- インサイドセールス SDR
- インサイドセールス企画
- オンラインセールス
- SaaS営業、MFBC
- インサイドセールス MFBC
- セールス MFBC
- マーケティングリサーチャー
- マーケター
- データマーケター
- BtoBマーケティングリーダー
- CRMスペシャリスト
- イベントマーケター
- Other
11月4日に入社しましたエンジニアの越川です。
本日は、私がコードを書く際に気をつけていることを書こうと思ったのですが、どう書くかに迷った末、ブログ記事駆動ハッカソンを行うことでそのプロセスで考えいたことなどを記事にすることにしました。
私はコードを書く際におもてなしの心が大事だと思っています。おもてなしの心は最終的なアウトプットに触れるユーザーはもちろんのこと、チームメンバー、未来の自身へ向けた思いやりです。
今回題材とするのは、KPTツールです。KPTは、日々の活動を振り返り「Keep」すべきこと「Problem」であること「Try」したいことを上げて、活動を振り返るために使われます。
先日行われた「オレたちが目指す”最強のエンジニアドリブン”」を終えた後に振り返りでKPT使ったので、それをWebアプリにしてみます。
今回のコードはすべて、ppworks/furikaeri/tree/v1.0.2に置いてあります。
機能一覧準備databaseのお掃除設定を足すFactoryGirlを便利に使う設定を足す初めてのテスト実行最初のテストを書く開発の流れProject を作るProject#key にユニークな値を設定する処理を追加するProjectsController を作るIssue を作るIssuesController を作るもっとテストしたい残りのテスト気になる点を直す画面は?終わりに
機能一覧
ユーザーはprojectを作成する事ができるシステムはprojectに対する一意のURLを発行するユーザーは(Keep, Problem, Try)から選択してissueを登録できるユーザーは登録したissueを削除できる
最低限必要な機能はここまで。
準備
今回は、rspecでテストを書きます。featureテストにはcapybaraを使ってみましょう。以下のように最低限必要なgemを用意します。
Gemfile
source 'https://rubygems.org'
gem 'rails', '4.1.8'
gem 'pg'
gem 'sass-rails', '~> 4.0.3'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'jquery-rails'
gem 'jbuilder', '~> 2.0'
group :development, :test do
gem 'spring'
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'faker'
gem 'database_rewinder'
gem 'capybara'
end
rspec/rspec-railsにあるように、rspecの設定ファイルをインストールします。
$ rails g rspec:install
spec/spec_helper.rbとspec/rails_helper.rbが生成されるので、不要な箇所を消すとこんな感じになります。
spec/rails_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
end
databaseのお掃除設定を足す
feature testを書く際に便利となる、amatsuda/database_rewinderを使い、データベースを綺麗にする設定を足します。
config.fixture_path = "#{::Rails.root}/spec/fixtures"
- config.use_transactional_fixtures = true
+ config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
+
+ config.before(:suite) do
+ DatabaseRewinder.strategy = :truncation
+ end
+
+ config.before(:each) do
+ DatabaseRewinder.clean_all
+ load "#{Rails.root}/db/seeds.rb"
+ end
+
+ config.after(:each) do
+ DatabaseRewinder.clean
+ end
end
FactoryGirlを便利に使う設定を足す
thoughtbot/factory_girlでダミーデータを用意します。テストの中で、FactoryGirl.createと書かずに、createと書けるようになり便利です。
config.after(:each) do
DatabaseRewinder.clean
end
+ config.include FactoryGirl::Syntax::Methods
初めてのテスト実行
$ rspec
No examples found.
Finished in 0.0002 seconds (files took 0.0468 seconds to load)
0 examples, 0 failures
全てはここからです。
最初のテストを書く
まだ何もないので、トップページを作りましょう。トップページに「ふりかえり」と表示されることを確認します。
なんてことないcontrollerとview、それとroutesを設定しましょう。
app/controllers/pages_controller.rb
class PagesController < ApplicationController
end
app/views/pages/top.html.haml
ふりかえり
config/routes.rb
Rails.application.routes.draw do
root to: 'pages#top'
end
テストは以下のように書いてみました。
featureでテストしたい機能を明記しますscenarioでどんな手続で何をexpect期待するのかを書くと分かりやすいと思います。
このケースでは、/にアクセスすると、ふりかえりという文字列が表示されることを確認してます。
spec/features/root_spec.rb
require 'rails_helper'
describe 'Root' do
feature 'visit / path' do
scenario do
visit root_path
expect(page).to have_content 'ふりかえり'
end
end
end
rspec spec/features/root_spec.rb
Root
visit / path
should text "ふりかえり"
Finished in 0.37442 seconds (files took 1.4 seconds to load)
1 examples, 0 failures
無事通りました。
開発の流れ
準備はここまで、開発に移りましょう。
Projectを作るProjectsControllerを作るIssueを作るIssuesControllerを作る
という流れで作ってみます。
Project を作る
rails g model project name:string key:string
migrationファイルを開いて、null: falseオプションを追加したり、add_indexでインデックスを貼っておきます。
db/migrate/20141126155514_create_projects.rb
class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.string :name, null: false
t.string :key, null: false
t.timestamps
end
add_index :projects, :key, unique: true
end
end
ダミーデータを用意して、
spec/factories/projects.rb
FactoryGirl.define do
factory :project, class: 'Project' do
name { Faker::Name.title }
key 'unique key value'
end
end
テストはこんな感じ。
spec/models/project_spec.rb
require 'rails_helper'
describe Project do
describe 'create project' do
subject { create(:project) }
it { expect(subject).to be_persisted }
end
end
単体テストでは、subject(対象)を意識して書くと分かりやすいです。何を対象に何をテストしたいのかを明確にします。 仲間が読んだ時に意図が伝わるようなにコードを書く ことを大切にしましょう。
$ rspec
Root
visit / path
should text "furikaeri"
Project
create project
should be persisted
Finished in 0.28907 seconds (files took 1.45 seconds to load)
2 examples, 0 failures
いいですね。
ここで今回、Project#keyは、ユニークであることが大事なので、その検証をしておきたいと思いました。
require 'rails_helper'
describe Project do
describe 'create project' do
subject { create(:project) }
it { expect(subject).to be_persisted }
end
+ describe 'create projects' do
+ let(:project_count) { 10 }
+ subject { create_list(:project, project_count) }
+ it do
+ expect {
+ subject
+ }.not_to raise_error
+ end
+ end
end
「ある振る舞いの結果、何かを期待する」場合には以下の様な記述が読みやすいかなーと思っております。
subject { cool_object.awesome_method }
it 'テストするぞ! do
expect {
subject
}.to change(Hoge, :fugo).from(:piyo).to(:puni)
end
同じように、ある振る舞いの結果、あるエラーが発生するというテストは以下のようにかけるので、今回はエラがー起きないことをnot_toを使い記述しました。
subject { cool_object.awesome_method }
it '例外が発生しちゃうテストするぞ! do
expect {
subject
}.to raise_error(RuntimeError)
end
テストにおけるnotは「ある事柄ではない」すべてがマッチするケースが通ってしまうので、慎重に使う必要があります。今回のケースでは例外が発生しないことだけを見ておきたいのであえて使いました。そういった 事情はコメントに書く と良いかもしれません。
さて、実行すると
rspec spec/models/project_spec.rb
Project
create project
should be persisted
create projects
should not raise Exception (FAILED - 1)
Failures:
1) Project create projects should not raise Exception
Failure/Error: expect {
expected no Exception, got #<ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_projects_on_key"
DETAIL: Key (key)=(indentified_key) already exists.
: INSERT INTO "projects" ("created_at", "key", "name", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"> with backtrace:
# ./spec/models/project_spec.rb:11:in `block (3 levels) in <top (required)>'
# ./spec/models/project_spec.rb:14:in `block (4 levels) in <top (required)>'
# ./spec/models/project_spec.rb:13:in `block (3 levels) in <top (required)>'
# ./spec/models/project_spec.rb:13:in `block (3 levels) in <top (required)>'
Finished in 0.28738 seconds (files took 1.42 seconds to load)
2 examples, 1 failure
見事にエラーが起きますね、なんせkeyの生成処理を書いていませんからね。そしてこのエラー、ちょっと気になるエラーだなと思いました。
railsのレイヤーではなくdbのレイヤーにまで到達しのエラーとなっているので、もうちょい手前でチェックしたいですね。なので、validationを追加します。
app/models/project.rb
class Project < ActiveRecord::Base
validates :key, uniqueness: true
end
そうするとエラー内容が変わります。
Project
create project
should be persisted
create projects
should not raise Exception (FAILED - 1)
Failures:
1) Project create projects should not raise Exception
Failure/Error: expect {
expected no Exception, got #<ActiveRecord::RecordInvalid: Validation failed: Key has already been taken> with backtrace:
# ./spec/models/project_spec.rb:11:in `block (3 levels) in <top (required)>'
# ./spec/models/project_spec.rb:14:in `block (4 levels) in <top (required)>'
# ./spec/models/project_spec.rb:13:in `block (3 levels) in <top (required)>'
# ./spec/models/project_spec.rb:13:in `block (3 levels) in <top (required)>'
railsのレイヤーで守ってくれている感が出ました。二重で守ることに関しては賛否両論があるかと思いますが、validationを書くことによるメリットとしてはrailsの分かりやすいメッセージを表示できるという点にあると思います。
validatesに失敗すると、project.errorsの中身にエラーのメッセージが保存されるので、それをユーザーに表示する選択肢が生まれますね。
Project#key にユニークな値を設定する処理を追加する
class Project < ActiveRecord::Base
validates :key, uniqueness: true
+ before_validation :set_key
+
+ private
+
+ def set_key
+ self.key = SecureRandom.hex
+ end
+end
今回は、rubyの標準ライブラリを使いました。SecureRandom.hexでランダムな文字列を作ってくれます。
この実装のおかげで、、、
$ rspec
Root
visit / path
should text "ふりかえり"
Project
create project
should be persisted
create projects
should not raise Exception
Finished in 0.31031 seconds (files took 1.43 seconds to load)
3 examples, 0 failures
久々のオールグリーン。
ProjectsController を作る
地味な工夫としては、インスタンスの生成処理はなるべくbefore_actionにまとめて、アクションで行う処理にフォーカス出来るようにしています。
app/controllers/projects_controller.rb
class ProjectsController < ApplicationController
before_action :set_project, only: [:show]
before_action :set_new_project, only: [:new, :create]
def new
end
def create
if @project.save
redirect_to @project, notice: 'created new project'
else
render 'new'
end
end
def show
end
private
def set_project
@project = Project.find_by(key: params[:key])
end
def set_new_project
@project = Project.new(project_params)
end
def project_params
params.fetch(:project, {}).permit(:name)
end
end
viewはform処理はpartialを分けるという癖をつけておくと、新規と更新のformを共通化出来て便利です。ただデザインの都合上分かれるということもありうるので、そこは後でリファクタリングでオッケーでしょう。
app/views/projects/_form.html.haml
= form_for(project) do |f|
= f.text_field(:name)
= f.submit
app/views/projects/new.html.haml
= render('form', project: @project)
app/views/projects/show.html.haml
%h1= @project.name
routesのポイントは、paramです。今回、projectのURLを/projects/xxxxxxxxという感じにしたいのでrailsのidを使いたくないのでresourcesが生成するルートにもkeyを使いたいのです。
config/routes.rb
Rails.application.routes.draw do
resources :projects, only: [:new, :create, :show], param: :key
root to: 'pages#top'
end
このおかげでrake routesすると
projects POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
project GET /projects/:key(.:format) projects#show
普段、:idとなるところが:keyになっていますよね。これで、contollerにて、実際は:idじゃないけどparams[:id]で受け取るみたいなつらいことが避けられます。
さらに、モデルで#to_paramを定義しておくとURLヘルパーでもわざわざkeyを渡さないで済みます(いつもどおりproject_path(@project)みたいに書ける)。定義しておきましょう。
diff:app/models/project.rb
class Project < ActiveRecord::Base
validates :key, uniqueness: true
+ before_validation :set_key
+
+ def to_param
+ key
+ end
private
def set_key
self.key = SecureRandom.hex
end
end
テストはこんな感じで、featureテストなのでscenarioにて手続きを明記します。ポイントは、withinで見るDOMの範囲を絞ることでテストの範囲を明確にするところです。それと、変わりがちな文言よりもcssのclassなどでfindしている点です。この辺はデザイナーさんやコーダーさんとの連携が非常に重要となる点ですね。
spec/features/projects_spec.rb
require 'rails_helper'
describe 'Projects' do
let(:new_project) { build(:project) }
feature 'create new project' do
let(:created_project) { Project.last }
scenario do
visit new_project_path
within('#new_project') do
find('#project_name').set(new_project.name)
find('input[type=submit]').click
end
expect(page).to have_content('created new project')
expect(page).to have_content(new_project.name)
expect(current_path).to eq project_path(created_project)
end
end
end
さて、テストを実行。
$ rspec
Projects
create new project
should eq "/projects/ac97ac5f7733e87451bfab767e30c121"
Root
visit / path
should text "ふりかえり"
Project
create project
should be persisted
Finished in 0.45112 seconds (files took 1.63 seconds to load)
3 examples, 0 failures
Issue を作る
rails g model〜は端折ります。
各projectはissueを複数持てるようにしたいというのと、Issue#status でKPTのkeep, problem, tryを示す事がポイントです。そうした処理はbrainspec/enumerizeを使うと便利です。
app/models/issue.rb
class Issue < ActiveRecord::Base
extend Enumerize
KPT = %w(keep problem try)
enumerize :status, in: KPT, scope: true, default: KPT.first
belongs_to :project
end
app/models/project.rb
class Project < ActiveRecord::Base
validates :key, uniqueness: true
before_validation :set_key
+ has_many :issues
def to_param
key
db/migrate/20141126215936_create_issues.rb
class CreateIssues < ActiveRecord::Migration
def change
create_table :issues do |t|
t.integer :project_id, null: false
t.string :title, null: false
t.string :status, null: false
t.timestamps
end
add_index :issues, [:project_id]
end
end
ダミーデータは、FactoryGirlのtraitを使うと、「ここではこういう条件のデータを使いたい」「こっちでは、こんな」というのが楽に扱えます。
ここでは、keepな状態のissueはcreate(:issue, :keep)と使う感じです。
spec/factories/issues.rb
FactoryGirl.define do
factory :issue, class: 'Issue' do
title { Faker::Name.title }
trait :keep do
status { :keep }
end
trait :problem do
status { :problem }
end
trait :try do
status { :try }
end
end
end
spec/models/issue_spec.rb
require 'rails_helper'
RSpec.describe Issue do
let(:project) { create(:project) }
describe 'create issue' do
subject { create(:issue, project: project) }
it { expect(subject).to be_persisted }
end
end
テストはこんな。通ります。
$ rspec
Projects
create new project
should eq "/projects/a41150e0851e47df8da365f3d3ecf8d8"
Root
visit / path
should text "furikaeri"
Issue
create issue
should be persisted
Project
create project
should be persisted
Finished in 0.41658 seconds (files took 1.47 seconds to load)
4 examples, 0 failures
IssuesController を作る
ポイントは、issueはprojectの詳細ページから作れれば良いので、作成・削除はredirect_to :backで戻るという点。
app/controller/issues_controller.rb
class IssuesController < ApplicationController
before_action :set_project
before_action :set_issue, only: [:destroy]
before_action :set_new_issue, only: [:create]
def create
if @issue.save
redirect_to :back, notice: 'created new issue'
else
redirect_to :back, notice: @issue.errors.full_messages.join(',')
end
end
def destroy
if @issue.destroy
redirect_to :back, notice: 'deleted new issue'
else
redirect_to :back, notice: @issue.errors.full_messages.join(',')
end
end
private
def set_project
@project = Project.find_by(key: params[:project_key])
end
def set_issue
@issue = @project.issues.find(params[:id])
end
def set_new_issue
@issue = @project.issues.build(issue_params)
end
def issue_params
params.require(:issue).permit(:title, :status)
end
end
viewはpartialだけの構成でprojectsから呼ぶイメージです。issuesのpartialsがどこにあるか?を探す際にviews/issuesから探すのは自然の流れです。 ここにあるだろう! という気持ちを妨げないようにしたいです。
app/views/issues/_form.html.haml
= form_for([project, issue]) do |f|
= f.text_field(:title)
= f.select(:status, Issue.status.options)
= f.submit
app/views/issues/_issue.html.haml
= issue.title
app/views/issues/_issues.html.haml
%ul{class: status}
= content_tag_for(:li, issues.with_status(status)) do |issue|
= render('issues/issue', issue: issue)
app/views/projects/show.html.haml
%h1= @project.name
= render('issues/form', project: @project, issue: Issue.new)
%h2 Keep
= render('issues/issues', issues: @project.issues, status: :keep)
%h2 Problem
= render('issues/issues', issues: @project.issues, status: :problem)
%h2 Try
= render('issues/issues', issues: @project.issues, status: :try)
issuesはprojectに紐づくのでリソースをnestedに表します。
config/routes.rb
Rails.application.routes.draw do
- resources :projects, only: [:new, :create, :show], param: :key
+ resources :projects, only: [:new, :create, :show], param: :key do
+ resources :issues, only: [:create, :destroy]
+ end
root to: 'pages#top'
end
テストはとりあえずざっくり、issueが作成出来るように
spec/features/issues_spec.rb
require 'rails_helper'
describe 'create new issue' do
let(:project) { create(:project) }
let(:new_issue) { build(:issue) }
feature 'create new issue' do
scenario do
visit project_path(project)
within('#new_issue') do
find('#issue_title').set(new_issue.title)
select(new_issue.status_text, from: 'issue_status')
find('input[type=submit]').click
end
expect(page).to have_content('created new issue')
within("ul.#{new_issue.status}") do
expect(page).to have_content(new_issue.title)
end
expect(current_path).to eq project_path(project)
end
end
end
テストの結果はこんな。
$ rspec
create new issue
create new issue
should eq "/projects/f7dfb9c9b04099d37412a1737443de6f"
Projects
create new project
should eq "/projects/4b5f4b9012fbac685983b6f44916a6ea"
Root
visit / path
should text "ふりかえり"
Issue
create issue
should be persisted
Project
create project
should be persisted
Finished in 0.53655 seconds (files took 1.5 seconds to load)
5 examples, 0 failures
もっとテストしたい
IssuesControllerのテストが足りないですね。keepしかカバーしていないので、他も書きます。
spec/features/issues_spec.rb
describe 'create new issue' do
let(:project) { create(:project) }
let(:new_issue) { build(:issue, status) }
context 'keep' do
let(:status) { 'keep' }
feature 'create new issue' do
scenario do
visit project_path(project)
within('#new_issue') do
find('#issue_title').set(new_issue.title)
select(new_issue.status_text, from: 'issue_status')
find('input[type=submit]').click
end
expect(page).to have_content('created new issue')
within("ul.#{new_issue.status}") do
expect(page).to have_content(new_issue.title)
end
expect(current_path).to eq project_path(project)
end
end
end
context 'problem' do
let(:status) { 'problem' }
feature 'create new issue' do
scenario do
visit project_path(project)
within('#new_issue') do
find('#issue_title').set(new_issue.title)
select(new_issue.status_text, from: 'issue_status')
find('input[type=submit]').click
end
expect(page).to have_content('created new issue')
within("ul.#{new_issue.status}") do
expect(page).to have_content(new_issue.title)
end
expect(current_path).to eq project_path(project)
end
end
end
end
problemまで書いて気づきます。これはもしや更にコピペする予感。。。 3度同じことをし始めたらまとめる というルールで進むのがお勧めです。3度目がくるぞ、という予感でDRYを意識しましょう。
ここは、shared_examples_forでまとめると綺麗になります。
spec/features/issues_spec.rb
require 'rails_helper'
shared_examples_for 'create new issue' do
feature 'create new issue' do
scenario do
visit project_path(project)
within('#new_issue') do
find('#issue_title').set(new_issue.title)
select(new_issue.status_text, from: 'issue_status')
find('input[type=submit]').click
end
expect(page).to have_content('created new issue')
within("ul.#{status}") do
expect(page).to have_content(new_issue.title)
end
expect(current_path).to eq project_path(project)
end
end
end
describe 'Issues' do
let(:project) { create(:project) }
let(:new_issue) { build(:issue, status) }
context 'keep' do
let(:status) { :keep }
it_behaves_like 'create new issue'
end
context 'problem' do
let(:status) { :problem }
it_behaves_like 'create new issue'
end
context 'try' do
let(:status) { :try }
it_behaves_like 'create new issue'
end
end
今回はこのテストだけでの利用だったので同じファイル内に書きましたが、他のテストでも使う場合はspec/support配下に置くとよいですね。
$ rspec
Issues
keep
behaves like create new issue
create new issue
should eq "/projects/351c621ef51c404d5d6ddd6cdad74619"
problem
behaves like create new issue
create new issue
should eq "/projects/94675fb6922599c0b3d98f0fef72af03"
try
behaves like create new issue
create new issue
should eq "/projects/2b5a00b0ec7d438dbd99009f9175147c"
Projects
create new project
should eq "/projects/13f8cf1a6dda2e837d2fbc1a898f2aa9"
Root
visit / path
should text "furikaeri"
Issue
create issue
should be persisted
Project
create project
should be persisted
Finished in 0.62318 seconds (files took 1.46 seconds to load)
7 examples, 0 failures
残りのテスト
削除処理を忘れていました。足しましょう。同じくshared_examples_forでスッキリと。
spec/features/issues_spec.rb
require 'rails_helper'
shared_examples_for 'create new issue' do
- feature 'create new issue' do
+ let(:new_issue) { build(:issue, status, project: project) }
+
+ feature do
scenario do
visit project_path(project)
within('#new_issue') do
@@ -19,22 +21,38 @@ shared_examples_for 'create new issue' do
end
end
+shared_examples_for 'delete an issue' do
+ let!(:issue) { create(:issue, project: project) }
+
+ feature do
+ scenario 'delete an issue' do
+ visit project_path(project)
+ within(".issue:last-child") do
+ find('.delete-link').click
+ end
+ expect(page).to have_content('deleted an issue')
+ end
+ end
+end
+
describe 'Issues' do
let(:project) { create(:project) }
- let(:new_issue) { build(:issue, status) }
context 'keep' do
let(:status) { :keep }
it_behaves_like 'create new issue'
+ it_behaves_like 'delete an issue'
end
context 'problem' do
let(:status) { :problem }
it_behaves_like 'create new issue'
+ it_behaves_like 'delete an issue'
end
context 'try' do
let(:status) { :try }
it_behaves_like 'create new issue'
+ it_behaves_like 'delete an issue'
end
end
さて、それなりに機能が出揃いました。
$ rspec
Issues
keep
behaves like create new issue
should eq "/projects/dd188d439deb814443c5057408657fa2"
behaves like delete an issue
delete an issue
problem
behaves like create new issue
should eq "/projects/91c6e9836acbe615a71eec52140e7ce4"
behaves like delete an issue
delete an issue
try
behaves like create new issue
should eq "/projects/685c2ce50f336a7ec7adc3482c76f764"
behaves like delete an issue
delete an issue
Projects
create new project
should eq "/projects/ac915e7de04cf5c8d5802ceed92c7bf1"
Root
visit / path
should text "furikaeri"
Issue
create issue
should be persisted
Project
create project
should be persisted
Finished in 0.81576 seconds (files took 1.47 seconds to load)
10 examples, 0 failures
気になる点を直す
/projects/xxxxx => /xxxxxにしたいトップページにdemoプロジェクトを表示したい
といった点を改善したいと思いました。その辺りは、ppworks/furikaeriにあげてあります。
画面は?
ここまでひと通りの実装をする際にウェブブラウザで確認することはありませんでした。コアな機能を実装する際にこのように最低限のテストを書きながら進めると、その後のUIの検討や機能調整の際にコアの部分を壊さないように勧めることが出来るようになります。
さて画面の確認は、
$ brew install postgresql
$ git clone git@github.com:ppworks/furikaeri.git
$ git checkout v1.0.2
$ bundle
$ rake db:create:all
$ rake db:migrate
$ rails s
して頂くとよろしいかと思います。もしくは、ppworks/furikaeri/tree/v1.0.2より
Heroku’ Buttonであなたのheroku環境へdeploy可能です。heroku buttonからdeployされるコードは随時バージョンアップしていくかもしれないので、今回の記事時点でのコードは、ppworks/furikaeri/tree/v1.0.2のコードを御覧ください:)
これは最低限の機能しか無いですし、画面のデザインもまだです。妄想としてはwebsocketで同時編集とかheroku buttonを設定すると熱いですね。pull requestももちろん受付中です。
終わりに
マネーフォワードでは、おもてなしの心を持ってコードを書くエンジニアを募集しています!
みなさまのご応募お待ちしております!pull req応募もお待ちしております:)
マネーフォワード採用サイト
https://recruit.moneyforward.com/