【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;」を足してやれば、インライン要素的な並び方をしながらも、上下の余白設定や、高さの設定が自由にできるようになります。
【Rails】初めてのHaml記法
Hamlとは
Hamlは、綺麗で簡潔なHTMLを書くためのマークアップ言語です。
PHPやRailsなど、Web系の言語・フレームワークで使われます。
Hamlの特徴
何と言っても、簡単に・綺麗に・生産的にwebアプリのビューを作ることができるのが魅力です。
この辺の特徴は、Hamlがどんな思想の元作られたのか知ると、より具体的に見えてきます。
Haml公式によると、4つのCore Principlesがあるそうです。
なるほど、綺麗に、無駄なく、分かりやすいコードが書けるように設計されてそうですね。
HamlをRailsに導入する方法
動作環境は以下の通り。
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公式より引用)
インデントは必須
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/tutorial.html
erb2hamlのgithubページ