n でNode.jsのバージョンを管理する ヘ(^o^)ノ
Installation
$ git clone git@github.com:tj/n.git $ cd n && make install
Usage
Installed versions
$ n
Install latest version
$ n latest
Install/Activating versions
$ n 6.3.0
Available list
$ n ls
Remove version
$ n rm 6.3.0
io.js
$ n io [command]
GitbookをGitHub Pagesで公開する ヘ(^o^)ノ
Gitbook
HTMLや電子書籍(PDF,EPUB,MOBI)にoutputできる
今回はHTMLをoutputして、GitHub Pagesのホスティング機能を使って公開してみます
GitHub Pages
Organization と Project Pages で使うことができる
今回はProject Pagesを使う
Project Pagesを使うにはビルド後のファイルを gh-pages
ブランチへpushする必要があります
[コード管理用]
https://github.com/username/projectname
[GitHub Pages]
https://username.github.io/projectname
Custom domainも使えるよ
Using a custom domain with GitHub Pages - User Documentation
CircleCI
GitHubなどと連携して自動でビルドやテストしてくれる
CircleCIを使ってmasterにpushされたら自動でビルドを実行し、 gh-pages
ブランチへpushする
ご注意
CircleCIの秘密鍵はread-only
なのでpushできない
なので、 read/write
な権限をもってる秘密鍵を登録する必要がある
参考
GitHub Managing deploy keys | GitHub Developer Guide
CircleCI Adding read/write deployment key - CircleCI
Package
gh-pages
ブランチへpushする為に使ったパッケージ
べんりすっね
Gitbook Boilerplate
なんか最近よくみるので作ってみました
ボイラープレートとかちょっとかっこいい( ˘ω˘)
使い方
ローカルにclone
$ git clone git@github.com:murajun1978/gitbook-boilerplate.git gitbook-sample $ cd gitbook-sample $ rm -rf .git
Gitbookのセットアップ
$ npm install $ npm run init
リポジトリにpush
$ git init $ git add . $ git commit -m "Initial commit" $ git remote add origin [remote URL] $ git push -u origin master
CircleCIの環境変数をセット
Project settings > Environment Variables
https://circleci.com/gh/[username]/[project-name]/edit#env-vars
name: USERNAME value: [username] name: EMAIL value: [email]
CircleCIでbuildを実行
Happy Hacking٩( ‘ω’ )و
RailsのPolymorphicでhas_oneするヘ(^o^)ノ
Polymorphicのhas_one関連を書いてる記事が少なかったので
ついでにPolymorphicのおさらいしておく
環境
モデルをgeneratorでつくる
# zshなんでエスケープしてますです $ bin/rails g model picture imageable:references\{polymorphic\} $ bin/rake db:migrate
class Picture < ActiveRecord::Base belongs_to :imageable, polymorphic: true end
できました
has_many
まずは has_manyから
関連モデルをgeneratorでつくる
$ bin/rails g model employee name $ bin/rake db:migrate
モデルにhas_manyを設定
class Employee < ActiveRecord::Base has_many :pictures, as: :imageable end
コンソールで確認してみる
$ bin/rails c -s > employee.imageable.create => #<Employee id: 1, name: nil, created_at: "2016-04-23 15:51:52", updated_at: "2016-04-23 15:51:52"> > employee.pictures.create => #<Picture id: 1, imageable_id: 1, imageable_type: "Employee", created_at: "2016-04-23 15:52:17", updated_at: "2016-04-23 15:52:17">
できました
has_one
さて、問題のhas_one
関連モデルをgeneratorでつくる
$ bin/rails g model product name $ bin/rake db:migrate
モデルにhas_oneを設定
class Product < ActiveRecord::Base has_one :picture, as: :imageable end
コンソールで確認してみる
$ bin/rails c -s > product = Product.create => #<Product id: 1, name: nil, created_at: "2016-04-23 15:58:33", updated_at: "2016-04-23 15:58:33"> > product.picture.create NoMethodError: undefined method `create' for nil:NilClass
怒られました
> product.create_picture => #<Picture id: 1, imageable_id: 1, imageable_type: "Product", created_at: "2016-04-23 16:10:46", updated_at: "2016-04-23 16:10:46">
できました
Polymorphicでhas_oneするケースが少ないかも( ˘ω˘)
そもそも、Polymorphic関係なかったんや、、
Happy Hacking٩( ‘ω’ )و
参考
Arrayでinjectを使ってみるヘ(^o^)ノ
injectはとても便利( ˘ω˘)
[1, 2, 3].inject(:+) #=> 6
こんな感じで読みやすくていい感じ
total_price = 90 total_price += [10, 20].inject(:+) #=> 120
Railsのバリデーションとかで使うならこんな感じかな
# 以下の値を仮定 limit_total_price = 100 total_price = 100 if items.map(&:price).inject(total_price, :+) > limit_total_price errors.add(:total_price, "over the limit") end # with ActiveSupport if items.map(&:price).sum > limit_total_price errors.add(:total_price, "over the limit") end
Happy Hacking٩( ‘ω’ )و
追記
- 2015/07/25 JunichiItoさんのコメ反映♪ Thanks!
TempingでMixinするmoduleのテストをしてみる٩( ‘ω’ )و
RailsでモデルにMixinするモジュールをテストしたいとき、みなさんどうしてますか?
mock_model? stub_model? 自分のダミーテーブル作る? 各モデルでテストする?
どれも意外と面倒くさい
そんなときはTempingを使うと楽ちん
ActiveSupport::Concernのモジュールをテストしてみましょう
# app/modules/logical_delete_scopes.rb module LogicalDeleteScopes extend ActiveSupport::Concern included do scope :without_deleted, -> { where(deleted_at: nil) } scope :only_deleted, -> { where.not(deleted_at: nil) } end end
ダミーのモデルを作る
# spec/support/dummy_model.rb Temping.create :dummy_model do include LogicalDeleteScopes with_columns do |t| t.datetime :deleted_at end end
テストコードを書く
# spec/modules/logical_delete_scopes_spec.rb require 'rails_helper' RSpec.describe LogicalDeleteScopes do let!(:enable_data) { DummyModel.create(deleted_at: nil) } let!(:deleted_data) { DummyModel.create(deleted_at: DateTime.now) } example do expect(DummyModel.without_deleted).to match_array [ enable_data ] expect(DummyModel.only_deleted).to match_array [ deleted_data ] end end
Tempingはtemporary tableを使ってるので物理テーブルにも残らない github.com
Happy Hacking٩( ‘ω’ )و
masterのBug Fixだけをreleaseブランチへマージする٩( ‘ω’ )و
GitHubにはrelease機能があります
Creating Releases - User Documentation
masterブランチにマージしてタグ付けてきたが、railsのブランチを見るとリリースブランチが存在します
いまさらですが、releaseブランチを作るGitLab Flowを導入しました ( ̄▽ ̄;)
そうするとmasterブランチの変更をreleaseブランチにマージしないとイケない時があります
例えば、Bug FixやSecurity Fixなどなど
では、masterブランチの特定commitだけmergeしてみよう
マージしたいcommitのidを確認する
$ git checkout master $ git log --oneline 602b23d bug fix / filter conditions 657c50a remove duplicates ...
602b23dだけを1-0-stableにマージするときはgit cherry-pick
を使います
$ git checkout 1-0-stable $ git cherry-pick 602b23d
これで特定のcommitだけmergeできました
Happy Hacking٩( ‘ω’ )و
d(゚Д゚ )☆スペシャルサンクス☆( ゚Д゚)b
action_controllerの拡張gemをRSpecでTDD ٩( ‘ω’ )و
action_controllerの拡張gemを作成するときにrspecでテストする
ユーザ認証のサンプルgemをTDDで作っていきましょう
まずは、gemのひな形を作る
$ bundle gem user_auth
bundlerが1.9系なら以下のファイルが作成されてるはず
├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin │ ├── console │ └── setup ├── lib │ ├── user_auth │ │ └── version.rb │ └── user_auth.rb ├── spec │ ├── spec_helper.rb │ └── user_auth_spec.rb └── user_auth.gemspec
さて、ここから本題です
ゴールはこんな感じで、認証に失敗したら例外みたいなー
class ApplicationControlller < ActionController::Base before_action :authenticate_user! end
TDDなのでテストから書いてくが、その前に開発時に必要なgemをインストール
# Gemfile source 'https://rubygems.org' gemspec # この3つを追加 gem 'rails' gem 'rspec-rails' gem 'sqlite3'
ざっとテスト書いていきまーす
# spec/user_authenticate_spec.rb require 'spec_helper' RSpec.describe UserAuth::UserAuthenticate do describe ApplicationController, type: :controller do controller do def index render text: 'success!' end end context 'Authentication failure' do example do expect { get :index }.to raise_error end end context 'Authentication success' do let(:user) { User.create(email: 'user@example.com') } example do session[:user_id] = user.id get :index expect(response.body).to eq 'success!' end end end end
テスト実行すると落ちます!
uninitialized constant UserAuth::UserAuthenticate (NameError)
UserAuthenticateがないよーって言ってるので作りましょう
# lib/user_auth/user_authenticate.rb module UserAuth module UserAuthenticate end end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' # 追加 require 'user_auth/user_authenticate'
テストを実行!
uninitialized constant ApplicationController (NameError)
ApplicationControllerがないって言ってるので、ダミーのコントローラーを作ります
# spec/support/action_controller.rb require 'action_controller/base' class ApplicationController < ActionController::Base end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' # 追加 require 'support/action_controller'
テストを実行!
'method_missing': undefined method 'controller'
RSpecのcontrollerメソッドがないっていってる。
これはrspec-railsのメソッドなので、spec_helperに追加
# spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' require 'support/action_controller' # 追加 require 'rspec/rails'
テストを実行!
undefined method 'application' for Rails:Module
applicationがないって言ってるのでダミーのRails::Applicationを作ります
# spec/support/application.rb require 'action_dispatch' module Rails class App def env_config; {} end def routes return @routes if defined? @routes @routes = ActionDispatch::Routing::RouteSet.new @routes.draw do resources :posts end @routes end end def self.application @app ||= App.new end end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' # action controllerより前に追加 require 'support/application' require 'support/action_controller' require 'rspec/rails'
テストを実行!
uninitialized constant User
Userがないって言ってるのでダミーのUserモデルを作ります
# spec/support/active_record.rb require 'active_record' ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') class User < ActiveRecord::Base; end class CreateAllTables < ActiveRecord::Migration def self.up create_table :users do |t| t.string :email end end end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' require 'user_auth/user_authenticate' require 'support/application' require 'support/action_controller' require 'rspec/rails' # 追加 require 'support/active_record' RSpec.configure do |config| config.before :all do CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'users' end config.before :each do User.delete_all end end
テストを実行!
For instance, 'include Rails.application.routes.url_helpers'.
そのまま、ダミーのApplicationControllerにincludeしてあげましょう
# spec/support/action_controller.rb require 'action_controller' class ApplicationController < ActionController::Base include Rails.application.routes.url_helpers end
テストを実行!
expected Exception but nothing was raised
キタ——(゚∀゚)——!!
ダミーのApplicationControllerにauthenticate_user!メソッドを追加しましょう
# spec/support/action_controller.rb require 'action_controller' class ApplicationController < ActionController::Base include Rails.application.routes.url_helpers before_action :authenticate_user! end
テストを実行!
undefined method 'authenticate_user!'
authenticate_user!メソッドを実装します
# lib/user_auth/user_authenticate.rb module UserAuth module UserAuthenticate def authenticate_user! end end end # lib/railtie.rb require 'rails/railtie' require 'active_support' module UserAuth class Railtie < Rails::Railtie ActiveSupport.on_load :action_controller do require 'user_auth/user_authenticate' send :include, UserAuth::UserAuthenticate end end end # lib/user_auth.rb require "user_auth/version" # 追加 require 'user_auth/railtie' ...
テストを実行!
expected Exception but nothing was raised
authenticate_user!メソッドでユーザを取得する
# lib/user_auth/user_authenticate.rb module UserAuth module UserAuthenticate def authenticate_user! User.find(session[:user_id]) end end end
テストを実行!
おーるぐりーんヾ( ̄∇ ̄=ノ
どうですか?
TDDなら次に何をするかが明確になりますよね?
テストを書いて、エラーがでたら原因を調べて解消していく
テストが失敗(エラーじゃないよ)したらロジックを書く!
そしてグリーンになればオッケーって感じです
サンプルコードは雑ですがね...
Happy Hacking٩( ‘ω’ )و