文系人間がエンジニアを目指すブログ

大学の文系学部を卒業した私が、ソフトウェアエンジニアになって、一人前を目指す過程を書くブログです。

【Javascript】「++」のような、インクリメント演算子の挙動には注意

インクリメント/デクリメント演算子ってなに?

JSのちょっと面白い挙動を勉強したので、備忘録も兼ねて書きます。

今回取り扱うのは、「インクリメント演算子」と「デクリメント演算子」というやつです。

x = ++x;
y = --y;

こんなやつ。

「++」がインクリメント演算子で、「--」がデクリメント演算子です。

こいつらが何をしているかというと、

x = x + 1;
y = y -1;

このように、変数自身に1を足したり引いたりしてくれています。

「++」を変数の前に置く(前置演算)のと、後ろに置く(後置演算)ので挙動が変わる

この演算子の注意点は、「置く場所を気をつけろ」ということです。

実は、インクリメント/デクリメント演算子は、変数の前にも後ろにも置くことができます。

それぞれ挙動が異なるので、注意が必要です。

前に置く場合の挙動(前置演算)

var a = 1;
var b = ++a;

console.log(a);
=>2

console.log(b);
=>2

変数a, b共に1足されていることがわかります。

「++」を変数の前に置くと、「変数aをインクリメントしてから、変数bに代入する」という挙動になります。

だから、どっちも2になっているわけですね。

後ろに置く場合の挙動(後置演算)

var a = 1;
var b = a++;

console.log(a);
=>2

console.log(b);
=>1

今度は変数bの中身が1のままで出力されました。

「++」を後ろに置くと、「変数aを変数bに代入してから変数aをインクリメントする」という挙動になります。

気をつけましょう。

参考図書

勉強に使ってるのがこの本。

Kindle版が見やすくなってておすすめです。

画像ベタ張りじゃなくて、ちゃんとKindle用にフォーマットされてて使いやすいです。

【Rspec】ネストされているコントローラーのテストについて。「No route matches」と言わせない書き方

この記事を書いた背景

題名の通りですが、ネストされているコントローラーのテストをRspecで書いていて、ややハマったので、書きました。

ネストの状況はこの通り。

Rails.application.routes.draw do
  devise_for :users
  root 'groups#index'
  resources :users, only: [:edit, :update]
  resources :groups, except: [:show, :destroy] do
    resources :messages, only: [:index, :create]
  end
end

今回テストしようとしていたのは、messagesコントローラーです。

ご覧の通り、groupsの下にネストされているので、indexとcreateのroutingが、

GET    /groups/:group_id/messages(.:format) messages#index
POST   /groups/:group_id/messages(.:format) messages#create

このようになっています。

そのため、messageをテストするにも、親となるgroupのidが必要になってくるのですね。

そこの書き方を示していきたいと思います。

開発環境

開発環境は以下の通り。

ruby '2.3.1'
'rails', '~> 5.1.6'
'rspec-rails' '3.7.2'
'factory_girl_rails', "~> 4.4.1"
'devise'

ネストされているコントローラーのテストをRspecで書く(indexアクション)

indexアクションのテストを例に説明していきます。

想定通りのインスタンスが取得できているか、レンダリング先は正しいか、ということをテストします。

まずは全体像を示しておきます。

require 'rails_helper'

describe MessagesController do
  let(:group) { create(:group) }
  let(:user) { create(:user) }

  describe '#index' do

    context 'log in' do
      before do
        login_user user
        get :index, params: { group_id: group.id }
      end

      it 'assigns @message' do
        expect(assigns(:message)).to be_a_new(Message)
      end

      it 'assigns @group' do
        expect(assigns(:group)).to eq group
      end

      it 'redners index' do
        expect(response).to render_template :index
      end
    end

    context 'not log in' do
      before do
        get :index, params: { group_id: group.id }
      end

      it 'redirects to new_user_session_path' do
        expect(response).to redirect_to(new_user_session_path)
      end
    end
  end
end

つらつらと書いていますが、一番言いたいのはココ!

      before do
        login_user user
        get :index, params: { group_id: group.id }
      end

beforeの記述部分の、「get :index, params: { group_id: group.id }」というところです。

なぜこんな書き方なのか?

もしネストしていないモデルのコントローラーだったら、

get :index

これだけで擬似的にアクションを呼び出すことが可能です。

しかし、ネストされているので、親モデルのidがパラメーターとして必要になります。

ゆえに、

params: { group_id: group.id }

で呼び出してあげる必要があるのでした〜。

注意点

ネストしていないモデルで、かつパラメータとしてidが必要なアクションがありますよね。例えば、showアクションとか。

それを呼び出すときは、

#gemのfactory_girl_railsを使用
group = create(:group)

get :show, id: group

こんな風に書きます。

筆者は、先ほどのネストされたモデルのアクションを呼び出すときに、同じノリで書いてしまい、プチハマりしました

group = create(:message)
get :index, group_id: group

こんな風に。

そうすると、「No route matches」と言われ続けます。

皆さんは筆者と同じ轍を踏まないようにしてくださいね(^^;)

【Rails】多対多のアソシエーションの組み方をまとめてみた。

そもそも、アソシエーションてなに?

アソシエーションというのは、モデルとモデルの関係性のことです。

例えば、twitterのような、tweetモデルとuserモデルを持っているアプリケーションを例に取ってみましょう。

userは、複数のtweetを投稿することができ、データベース上では、一人のuserが複数のtweetを持っている状態にあります。

反対に、tweetは一人のユーザーによってのみ作られますから、データベース上では、一つのtweetが一人のuserを持っている状態にあります。

このような、モデル同士の関係のことをアソシエーションと呼びます。

アソシエーションを組むと何ができるようになるの?

アソシエーションを組むと、関連付けたモデルのデータを取得でき、大変便利です。

というか、アソシエーションなしでは複雑なアプリケーションは作れないので、必須の機能と言っても過言ではありません。

例えば、tweetを表示する際に、tweetに紐づいたuserのデータを取得できるので、「誰がこのtweetをしたのか」ということを簡単に表示させることができます。

多対多のアソシエーションってなに?

では、多対多のアソシエーションとは何でしょうか?

先ほどのtweetの例では、

という関係でしたが、この関係性が複数x複数に変わります。

userモデルとgroupモデルを持っているようなアプリケーションを例に考えます。

userの視点から見ると、userは複数のgroupに所属することができます。

また、groupの視点から見ても、groupは複数の所属userを持っているような状態になります。

  • user => 複数のgroups
  • group => 複数のusers

という関係性になります。これが多対多のアソシエーションです。

実装の手順

それでは、実際にuserモデルとgroupモデルの多対多の関係を作っていきましょう!!

ちなみに、今回の実装環境は、

ruby '2.3.1'
gem 'rails', '~> 5.1.6'

となっております。

多対多のアソシエーションを作りたい2つのモデルを作成

まずは、多対多の関係を組む2つのモデルを作成。

bundle exec rails g model user
bundle exec rails g model user

カラム名や制約を適宜追加して、

bundle exec rake db:migrate

しましょう!

2つのモデルをつなぐ、中間モデルを作成

userモデルとgroupモデルの二つを繋ぐ、中間モデルを作成します。

bundle exec rails g model member

Migrationファイルが作成されるので、中身を変更していきますが、ここで注意点があります。

【Caution!!】中間テーブルのMigrationファイルでの、reference型の外部キーの設定方法

「モデルを作成したら、いざテーブルを作ろう!」ということで、Migrationファイルを編集。

ここで、

create_table :members do |t|
    t.references           :user_id, null: false, foreign_key: true
    t.references           :group_id, null: false, foreign_key: true
    t.timestamps
end

このように、カラム名を「xx_id」みたいな形で書いてしまうと、

Mysql2::Error: Cannot add foreign key constraint

とか、

ActiveRecord::StatementInvalid: Mysql2::Error: Table 'CB名.テーブル名' doesn't exist

って出てしまいますので、

create_table :members do |t|
    t.references           :user, null: false, foreign_key: true
    t.references           :group, null: false, foreign_key: true
    t.timestamps
end

このように、「_id」はなしで書きましょう。

references型を指定するときは、「_id」を書いてなくても、「user_id」とか「group_id」というカラム名で登録してくれます。

integer型で外部キーを設定する方法に慣れている人は間違えやすいと思うので、気をつけましょう。

3つのモデルのアソシエーションを組む

今作った3つのモデルのアソシエーションを組んでいきます。

ポイントは、「中間テーブルを通じた多対多の関係をどう書くのか?」という点です。

user.rb(多対多の関係を組むモデル)

has_many :groups, through: :members
has_many :members

group.rb(多対多の関係を組むモデル)

has_many :users, through: :members
has_many :members

member.rb(中間モデル)

belongs_to :user
belongs_to :group

このように書きます。

【CSS Tip】インライン要素にはmarginの上下が効かない問題とその対策

aタグにmargin-topをかけようと思ったら効かなかった

CSSのmarginに関するヒントをご紹介します。

僕がこの問題に出会ったのは、aタグのmargin-topを取りたいと思っていた時でした。

margin-topをいくらかけても全く効かない。

なのに、line-heightや、margin-right&left、paddingはなぜか効いている。。

ググってみると、どうやらインライン要素はそういう風にできているらしい。

対処法

対策はそんなに難しくありません。

margin-top: 20px;
display: inline-block;

このように、「display: inline-block;」を足してやれば、インライン要素的な並び方をしながらも、上下の余白設定や、高さの設定が自由にできるようになります。

【CSS】「height: 100%;」が効かない時に確認すべきこと

heightが100%になってくれない

cssでよく使うのがheightやwidthを画面の100%にする方法です。

これが効かなくなった時に、確認すべきことをご紹介します。

親要素となるhtmlやbodyの高さはどうなっているか?

これを確認しましょう。

もし、リセットcss以外に設定がなかったら、以下のように書きましょう。

Scssだと、

html{
  height: 100%;
  body{
    height: 100%;
  }
}

私はこれを試したら解決しました。

【Rails】初めてのHaml記法

Hamlとは

Hamlは、綺麗で簡潔なHTMLを書くためのマークアップ言語です。

PHPRailsなど、Web系の言語・フレームワークで使われます。

Hamlの特徴

何と言っても、簡単に・綺麗に・生産的にwebアプリのビューを作ることができるのが魅力です。

この辺の特徴は、Hamlがどんな思想の元作られたのか知ると、より具体的に見えてきます。

Haml公式によると、4つのCore Principlesがあるそうです。

  1. マークアップは美しくあるべき
  2. マークアップはDRYであるべき
  3. マークアップは整然とインデントされているべき
  4. HTMLの構造が分かりやすくあるべき

なるほど、綺麗に、無駄なく、分かりやすいコードが書けるように設計されてそうですね。

HamlRailsに導入する方法

では、RailsHamlを導入していきましょう。

動作環境は以下の通り。

rails '~> 5.1.6'
ruby '2.3.1'

GemfileにHamlを入れる

gem 'haml-rails'
gem 'erb2haml'

'erb2haml'は、その名の通り、erbをhamlに(erb to haml)変換するgemです。

READMEを見てみると、「ERBをHamlに変換したり、置き換えたりするRake tasksを提供するよ」と書いてあります。

rakeコマンドを使って変換できるようになるみたいですね。

GitHub - dhl/erb2haml: Simple script to bulk covert ERB files in a Rails app to Haml

コマンド一つでerbファイルをhamlファイルに変えることが可能

'erb2haml'のおかげで、コマンド一つで簡単にビューファイルをHamlにしちゃうことが可能。

元々あったerbファイルを残しておきたい場合

rake haml:convert_erbs

erbファイルを消して、Hamlファイルに置き換えちゃいたい場合

rake haml:replace_erbs

Hamlの基本的な使い方をHaml公式チュートリアルで見てみる

ここからは基本的な使い方を書いていきますよ。

"%"と"="を使って書く

Hamlでは、普通のhtmlファイルやerbファイルと違い、タグで要素を囲むことはしません。

例えば、headerとhタグだけの簡単なhtmlだと、

%header
  %h5 hello world

このようになります。タグで囲む代わりに、「%タグ名」と書くことになります。

Railsの場合だと、ビューファイルで埋め込みRubyを使うことがあると思いますが、そんな時は以下のように書きます。

%strong= item.title

これはerbで言う所の、

<strong><%= item.title %></strong>

です。(コード例はHaml公式より引用)

Haml :: Tutorial

インデントは必須

erbや普通のhtmlと違うのは、入れ子構造になっている際にはインデントが必須となっていること。

インデントされていないと正しく認識してくれませんので、ご注意を。

classとか付けるにはどうするの?

続いて、haml記法でclassなどの属性を付けていきます。

%div{:class => "myclass", :id => "myid"} Hello World

このようにします。

divタグ、class、idの省略した書き方がある

先ほどのコードですが、divタグ、class、idはあまりにたくさん出てくるので、css風に省略して書くことができるようにしてくれています。

.myclass#myid Hello World

なんと、%まで省略可能!これはコードがスッキリしそう。

参考サイト

Haml公式サイト

http://haml.info/

Haml公式チュートリアル

http://haml.info/tutorial.html

erb2hamlのgithubページ

https://github.com/dhl/erb2haml