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
Three.js
機能参加したThree.js入門者向けハンズオンでいじったものの残骸。Three.js触りだけだったけれど、もう少し勉強して思う通りのものが作れるようになれば楽しいかと思う。
■
只今第10章
Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
Railsは、form_for(@user)を使用してフォームを構成すると、@user.new_record?がtrueのときにはPOSTを、falseのときにはPATCHを使用します。
rails賢い。
JSON serverとダミーJSONの作成方法
サーバーサイドのAPI実装がまだできていない場合に使用できる。
www.webprofessional.jp