グループ
こんなデータがあるとして、
[ { name: "筒香", bats: 5, hits: 3 }, { name: "ロペス", bats: 5, hits: 2 }, { name: "宮崎", bats: 5, hits: 4 }, { name: "筒香", bats: 4, hits: 2 }, { name: "ロペス", bats: 4, hits: 4 }, { name: "宮崎", bats: 4, hits: 4 }, ]
こんな結果が欲しいとき
[ {:name=>"宮崎", :bats=>9, :hits=>8}, {:name=>"ロペス", :bats=>9, :hits=>6}, {:name=>"筒香", :bats=>9, :hits=>5}, ]
rubyでこんな風に書いた
records = [ { name: "筒香", bats: 5, hits: 3 }, { name: "ロペス", bats: 5, hits: 2 }, { name: "宮崎", bats: 5, hits: 4 }, { name: "筒香", bats: 4, hits: 2 }, { name: "ロペス", bats: 4, hits: 4 }, { name: "宮崎", bats: 4, hits: 4 }, ] ans = records.each_with_object([]) do |item, memo| if ev = memo.detect{ |ev| item[:name] == ev[:name] } ev.merge!(item.merge(bats: item[:bats] + ev[:bats], hits: item[:hits] + ev[:hits])) else memo << item.dup end end .sort_by{|h| -h[:hits] } p ans # [ # {:name=>"宮崎", :bats=>9, :hits=>8}, # {:name=>"ロペス", :bats=>9, :hits=>6}, # {:name=>"筒香", :bats=>9, :hits=>5} # ]
SQLのほうがシンプルに書ける。
# create table create table bayrecord ( name varchar(20), bats int, hits int ); # insert data insert into bayrecord values ('筒香', 5, 3); insert into bayrecord values ('ロペス', 5, 2); insert into bayrecord values ('宮崎', 5, 4); insert into bayrecord values ('筒香', 4, 2); insert into bayrecord values ('ロペス', 4, 4); insert into bayrecord values ('宮崎', 4, 4); # select select name, sum(bats), sum(hits) from bayrecord group by name order by sum(hits) desc;
Vue.jsの何が嬉しいのか?
前職ではいわゆる静的なWebサイトを主に作成していたので基本jQueryで事足りていたのだが、Webアプリ制作会社に移ってからはプロジェクトにVue.jsが使われており、Vue.jsのレールに乗るような書き方をする必要が出てきた。 最初は完全にjQuery脳だったためVue.jsの書き方になじめず苦労をしたが、慣れてくるにつれその良さや、使われる理由が身をもってわかるようになってきた。
実感したのは以下の点
- DOMとデータが分離されているので両者を完全に分けて考えることができる。
- グローバル汚染が起こらない。
- 適切にコンポーネント化しておけば後の案件でも使いまわせる。
- 役割がコンポーネント単位ではっきりしているので機能拡張がしやすい。
jQueryはちょっとしたDOM操作を手軽に行えるが、今はDOM操作もプレーンなjsで十分に行えるようになったし、規模の大きいものをjQueryだけで書くと途端にスパゲティになってしまう。Vue.jsとjQueryでは提供してくれるものが違うので優劣をつけるものでもないけれど。
今後も遊びで作るものなどにもjQueryの代わりに使って更に体に覚え込ませでいく。
2016年オリックス・バファローズの勝率とポンタの歩み
高校野球の優勝回数を県別にまとめてみた
県別甲子園優勝回数
D3.jsで日本地図を描き、県別の優勝回数データと連携させビジュアライズしてみた。
こうしてみると優勝旗が白河の関を越えていないのがはっきりわかる。
(東北勢の優勝が条件なので北海道の優勝は入れないらしい)
また開催地である兵庫県に近い地域に優勝が集中しているのもわかる。(滋賀県頑張れ)
九州では宮崎県だけ春夏ともまだ優勝がない。
【参考】
D3.jsで日本地図を作成しデータを反映するサンプル(コロプレス地図) | Tips Note by TAM
また、これを作るにあたってweb上のデータを色々見たが、「朝鮮、台湾、満州」という地域があり驚いた。
戦前は外地からも甲子園に参加していたのは知らなかった。
台湾代表の活躍を描いたこちらの映画、見てみよう。
kano1931.com
vue.jsによる絞り込み
See the Pen data filtering by vue.js by tamoriinu (@yokoyama) on CodePen.
Spring man
rails使用中に何かとspringサーバーが重複して立ち上がることが多い。
springサーバーの確認と止める方法がrails tutorialにまとまっているのでメモ
https://railstutorial.jp/chapters/static_pages?version=5.0#aside-processes
Active Recordの関連付け
Active Recordの関連付けを理解するために、Railsガイドの以下のページを自分用にまとめた。 あくまで自分で理解するためのまとめなので関連付けを学びたい人は以下のページを見たほうがよいです。
https://railsguides.jp/association_basics.html
Active Record の関連付け (アソシエーション)
1 関連付けを使用する理由
関連付けをすることで、コード内で行われる操作を簡単にできる。
例) 顧客モデル: Customer 注文用モデル: Order ・1人の顧客は、多くの注文を行うことができる。
各モデル
class Customer < ActiveRecord::Base end
class Order < ActiveRecord::Base end
関連付けなしの場合に、既存の顧客のために新しい注文を1つ追加する
@order = Order.create(order_date: Time.now, customer_id: @customer.id)
顧客を削除する。 注文を消してから顧客を削除する必要がある。
@orders = Order.where(customer_id: @customer.id) @orders.each do |order| order.destroy end @customer.destroy
Active Recordの関連付けを使用して、2つのモデルにつながりがあることを 明示的に宣言することで、モデル操作が一貫する。
class Customer < ActiveRecord::Base has_many :orders, dependent: destroy end
class Order < ActiveRecord::Base belongs_to :customer end
関連付けされた場合の既存顧客への新しい注文追加方法。
@order = @customer.orders.create(order_date: Time.now)
関連付けされた場合の既存顧客の削除方法。顧客の注文もまとめて削除される。
@customer.destroy
2 関連付けの種類
Railsでサポートされている関連付けは以下の6種類
- belongs_to
- has_one
- has_many
- has_many :through
- has_one :through
- has_and_belongs_to_many
2.1 belongs_to関連付け
belongs_to
関連付けを行うと、他のモデルとの間に「1対1」の繋がりが設定される。
- 顧客(customer)
- 注文(order) 1つの注文につき正確に1人の顧客だけを割り当てたい場合
class Order < ActiveRecord::Base belongs_to :customer end
customer
は「単数形」
2.2 has_one関連付け
has_oneも他のモデルとの間に「1対1」の関連付けを設定するが、belongs_to
と違い、その宣言が行われているモデルのインスタンスが、他方のモデルのインスタンスを「まるごと含んでいる」または「所有している」ことを示す。
- 供給者(supplier)
- アカウント(account) 供給者1人につきアカウントを1つだけ持つ
class Supplier < ActiveRecord::Base has_one :account end
2.3 has_many 関連付け
has_many
関連付けは、他のモデルとの間に「1対多」の繋がりがあることを示す。
has_many
関連付けが使用されている場合、反対側のモデルではbelongs_to
が使用されることが多い。
has_many
関連付けが行われているモデルのインスタンスは、反対側のモデルの「0個以上の」インスタンスを所有する。
- 顧客(customer)
- 注文(order)
class Customer < ActionRecord::Base has_many :orders end
orders
のように「複数形」にする必要がある
2.4 has_many :throush関連付け
has_many :throush
関連付けは、他方のモデルと「多対多」の繋がりを設定する場合に使用される。
2つのモデルの間に「第3のモデル」(結合モデル)が介在する。モデルに対応するテーブルは「中間テーブル」と呼ばれる。
相手モデルの「0個以上」のインスタンスとマッチする。
- 患者(patient)
- 医師(physician)
- 診察予約(appointment)
患者は複数の医師にかかることができる。 医師は複数の患者を見ることができる。
class Physician < ActiveRecord::Base has_many :appointments has_many :patients, through: :appointments end
class Appointment < ActiveRecord::Base belongs_to :physician belongs_to :patient end
class Patient < ActiveRecord::Base has_many :appointments has_many :physicians, through: :appointments end
患者と医師の関連性を考えれば自ずと結合モデルの名前も連想できる(はず)
Rails1~2の頃はphisicians_patients
のような命名規則が推奨されていたらしいが、今は極力テーブル名(モデル名)自体に意味を持たせる形が推奨されている。
ネストしたhas_many
関連付けを介して「ショートカット」を設定することができる。
- document
- section
- paragraph
1つのdocumentは多数のsectionを持つ。 1つのsectionの下に多くのparagraphがある。
class Document < ActiveRecord::Base has_many :sections has_many :paragraphs, through: :sections end
class Section < ActiveRecord::Base belongs_to :document has_many :paragraphs end
class Paragraph < ActiveRecord::Base belongs_to :section end
documentは配下のparagraphsに以下のようにアクセスできる
@document.paragraphs
2.5 has_one :through関連付け
has_one :through
関連付けは、他のモデルとの間に1対1の繋がりを設定する。
2つのモデルの間に「第3のモデル」(結合モデル)が介在する。これによって、相手モデルの1つのインスタンスとマッチする。
- 提供者(supplier)
- アカウント(account)
- アカウント履歴(account_history)
1人の提供者が1つのアカウントに関連付けられる。 1つのアカウントが1つのアカウント履歴に関連付けられる。
class Supplier < ActiveRecord::Base has_one :account has_one :account_history, through: :account end
class Account < ActiveRecord::Base belongs_to :supplier has_one :account_history end
class AccountHistory < ActiveRecord::Base belongs_to :account end
2.6 has_and_belongs_to_many関連付け
has_and_belongs_to_many
関連付けは、他方のモデルと「多対多」の繋がりを作成する。
through:
を指定した場合と異なり、第3のモデル(結合モデル)が介在しない。
ただし結合用のテーブルは必要。
- 完成品(assembly)
- 部品(part)
1つの完成品に多数の部品が対応。 1つの部品にも多数の完成品が対応。
class Assembly < ActiveRecord::Base has_and_belongs_to_many :parts end
class Part < ActiveRecord::Base has_and_belongs_to_many :assemblies end
2.7 belongs_toとhas_oneのどちらを選ぶか?
2つのモデルの間に1対1の関係を作りたい場合、いずれか一方のモデルにbelongs_toを追加し、 もう一方のモデルにhas_oneを追加する必要がある。 では、どちらの関連付けをどちらのモデルに置けばよいのか?
- 外部キー(foreign key)をどちらに置くか テーブルに外部キーを置いた方のモデルにbelongs_toを追加する。(これだけでは決まらない)
has_oneは「所有している」ことを表す。主語となるモデルが目的語となるモデルを所有している、と考える。
◯供給者がアカウントを持っている
- ☓アカウントが供給者を持っている
class Supplier < ActiveRecord::Base has_one :account end
class Account < ActiveRecord::Base belongs_to :supplier end
マイグレーション中では外部キーは以下のように指定する
t.integer :supplier_id
Rails4以上ならば以下のように記述できる
t.references :supplier
2.8 has_many :throughとhas_and_belongs_to_manyのどちらを選ぶか?
「多対多」のリレーションシップ宣言にどちらを選ぶか?
- has_and_belongs_to_many
簡単に記述可能。関連付けを直接指定できる。 リレーションシップのモデルで何か特別なことをする必要がないならば結合モデルの不要な こちらを選ぶべき。ただし、専用の結合テーブルはDB上に作る必要がある。
- has_many :through
結合モデルを使用した間接的な関連付けとなる。 リレーションシップのモデル自体を独立したエンティティとして扱いたい(両モデルの関係そのものについて処理を行いたい)のであればこちらを選ぶべき。 結合モデルでvalidation, callback, 追加の属性が必要であればこちらを使用。
2.9 ポリモーフィック関連付け
ポリモーフィック関連付けを使用すると、ある1つのモデルが他の複数のモデルに属していることを、1つの関連付けだけで表現することができる。
- 写真(picture)
- 従業員(employee)
- 製品(product)
写真モデルは従業員モデルと製品モデルの両方に従属する。
class Picture < ActiveRecord::Base belongs_to :imageable, polymorphic: true end
class Employee < ActiveRecord::Base has_many :pircures, as: :imageable end
class Product < ActiveRecord::Base has_many :pictures, as: :imageable end
@employee.pictures
とすると、写真のコレクションをEmployeeモデルのインスタンスから取得できる。
@product.pictures
とすれば写真のコレクションをProductモデルのインスタンスから取得できる。
Pictureモデルのインスタンスがあれば、@picture.imageableで親を取得できる。ポリモーフィックなインターフェイスを使用するモデルで、外部キーのカラムと型のカラムを両方とも宣言しておく必要がある。
class CreatePictures < ActiveRecord::Migration def change create_table :pictures do |t| t.string :name t.integer :imageable_id t.string :imageable_type t.timestamps end end end
t.referencesを使用すると更にシンプルにできる。
class CreatePictures < ActiveRecord::Migration def change create_table :pictures do |t| t.string :name t.references :imageable, polymorphic: true t.timestamps end end end
controllerも含めた具体的な実装方法
http://ruby-rails.hatenadiary.com/entry/20141207/1417926599
2.10 自己結合
自分自身に関連付けられる必要のあるモデルに使用。
- 従業員(employee)
同じ従業員の中で、マネージャーと部下の関係を追えるようにしておきたい。
class Employee < ActiveRecord::Base has_many :subordinates, class_name: "Employee", foreign_key: "manager_id" belongs_to :manager, class_name: "Employee" end
上のように宣言しておくと、@employee.subordinates
と
@employee.manager
が使用できるようになる。
マイグレーション及びスキーマでは、モデル自身にreferencesカラムを追加する。
class CreateEmployees < ActiveRecord::Migration def change create_table :employees do |t| t.references :manager t.timestamps end end end
3 ヒントと注意事項
Active Recordの関連付けを効率的に使用するためには、以下について知っておく必要がある。
- キャッシュ制御
- 名前衝突の回避
- スキーマの更新
- 関連付けのスコープ制御
- 双方向関連付け
3.1 キャッシュ制御
関連付けのメソッドは、全てキャッシュを中心に構築されている。最後に実行したクエリの結果はキャッシュに保持され、次回以降の操作で使用される。
customer.orders # DBからordersを取得 customer.orders.size # ordersのキャッシュコピーが使用される customer.orders.empty? # ordersのキャッシュコピーが使用される
では、キャッシュのではなくDBから再度読み込むにはどうすればよいか?
customer.orders # DBからordersを取得 customer.orders.size # ordersのキャッシュコピーが使用される customer.orders(true).empty? # ordersのキャッシュコピーが破棄される。 #その後DBから再度読み込まれる
3.2 名前衝突の回避
関連付けを作成すると、モデルにその名前のメソッドが追加される。
ActiveRecord::Baseのインスタンスで既に使用されているような名前を関連付けに使用すると、基底メソッドが上書きされる。
例として、attributes
やconnection
は関連付けに使ってはいけない。
3.3 スキーマの更新
関連付けを使用するにはその設定に合わせてDBのスキーマを常に更新しておく必要がある。
- belongs_to関連付けを使用する場合は、外部キーを作成する必要がある。
- has_and_belongs_to_many関連付けを使用する場合は、適切な結合テーブルを作成する必要がある。
3.4 関連付けのスコープ制御
Active Recordモデルをモジュール内で宣言している場合など、異なるスコープ内で定義されている場合は、関連付けの宣言で完全なクラス名を指定する必要がある。
3.5 双方向関連付け
関連付けは、通常双方向で設定する。2つのモデル両方に関連を定義する必要がある。
class Customer < ActiveRecord::Base has_many :orders end class Order < ActiveRecord::Base belongs_to :customer end
Active Recordは、これら双方向関連付け同士に繋がりがあることをデフォルトでは認識しない。これによって以下のようにオブジェクトの2つのコピー同士で内容が一致しなくなることがある。
c = Customer.first o = c.orders.first c.first_name == o.customer.first_name # => true c.first_name = 'Manny' c.first_name == o.customer.first_name # => false
なぜこういうことが起こるのかというと、c
とo.customer
は同じデータがメモリ上で異なる表現となっており、一方が更新されても他方が自動で更新されないため。
Active Recordの:inverse_of
オプションを使用すればこれらの関係を通知することができる。
inverse of ~ : 「~の逆」の意味
class Customer < ActiveRecord::Base has_many :orders, inverse_of: :customer end class Order < ActiveRecord::Base belongs_to :customer, inverse_of :orders end
上のように変更することで、Active Recordはcustomerオブジェクトのコピーを1つだけ読み込むようになる。 不整合を防ぎ、アプリケーションの効率も高まる。
c = Customer.first o = c.orders.first c.first_name == o.customer.first_name # => true c.first_name = 'Manny' c.first_name == o.customer.first_name # => true
inverse_ofの制限
- :through関連付けと併用することはできない
- :polymorphic関連付けと併用することはできない
- :as関連付けと併用することはできない
- belongs_to関連付けの場合、has_manyの逆関連付けは無視される
以下のオプションを設定した関連付けでは、逆関連付けは自動的には設定されない
- :conditions
- :through
- :polymorphic
- :foreign_key