#author("2022-07-15T07:56:16+00:00","default:src128","src128") #author("2022-07-15T08:48:47+00:00","default:src128","src128") &tag(ActiveRecord); *目次 [#t9585ef4] #contents *参考情報 [#xd595ebe] -[[読書メモ+tips+日記:[Ruby] ActiveRecord を単体で(Railsアプリの外で)使う:http://blog.livedoor.jp/takaaki_bb/archives/50602246.html]] -[[ActiveRecord を 単独で使う例: katoy: cocolog:http://youichi-kato.cocolog-nifty.com/blog/2008/06/activerecord_0c49.html]] -[[Active Record クエリインターフェイス | Rails ガイド:http://railsguides.jp/active_record_querying.html]]…ここが一番分かりやすい *スコープ [#m621287a] -おおむねstaticメソッドだがnilを返すとallとなるところが異なる。 *検索 [#pba5c11a] **概要 [#wec34d52] -[[Rails 4で非推奨になった/なっていないfinderメソッドを整理する - Qiita:http://qiita.com/jnchito/items/2b7d64851665071ed6e6]] -[[rails/activerecord-deprecated_finders:https://github.com/rails/activerecord-deprecated_finders]] -dynamic finderが全て非推奨になったわけではない(find_by_nameのような)。 **IDや項目で検索 [#wd1c188e] -findを使う。レコードが存在しない場合例外発生 book = Book.find(999) -find_by_idを使う。レコードが存在しない場合nil。 book = Book.find_by_id(999) book = Book.find_by_name('おもしろい本') book = Book.find_by_name!('おもしろい本') #=>例外発生たい場合 -find_by(ハッシュ)を使う。レコードが存在しない場合nil book = Book.find_by(id: 999) book = Book.find_by(name: 'おもしろい本') book = Book.find_by!(name: 'おもしろい本') #=>例外発生させたい場合 book = Book.find_by(name: 'おもしろい本', price: 100) #=>2項目のAnd検索。 **whereで条件指定 [#x0fdb833] -[[Active Record クエリインターフェイス | Rails ガイド:https://railsguides.jp/active_record_querying.html]]が詳しい -whereで指定できる条件には、文字列、配列、ハッシュなど。 -Are系は存在しない場合空配列となる。firstで先頭要素を取得する。 book = Book.where("title=?", title).first -文字列で検索したい場合 books = Book.where("title='abc'") -配列で検索。"?"でプレースホルダを指定できる。 books = Book.where("title=? AND price=?" title, price) -ハッシュで指定。キーにフィールド、ハッシュ値にその値。複数指定した場合AND条件となる。 books = Book.where(title: 'abc') books = Book.where('title' => 'abc') books = Book.where(title: 'abc', author: 'def') **関連オブジェクトを使って検索 [#k3f0338f] -includesやjoinsを使って検索できる。[[includes (ActiveRecord::QueryMethods) - APIdock:http://apidock.com/rails/ActiveRecord/QueryMethods/includes]] -例えば以下の通り #pre{{ users = User.includes(:address) users.each do |user| user.address.city end User.includes(:posts).where('posts.name = ?', 'example').references(:posts) }} -ここでincludesに指定するのは関連の名前(belongs_toやhas_manyで指定する名前)であるのに対し、referencesで指定するのはテーブルの名前(複数形の名前)でないといけないことに注意。whereの中に記述するのもテーブル名。 -referencesはテーブル参照が必要なことを明示している。これは例えばメールアドレスを検索する場合にドットが含まれている場合にまずいのの対策らしい。[[【Rails3.2】【バッドノウハウ】includes 使用時に where で ドットを使うと想定外になるかも知れない件、または、なぜRails4 から references が必要になったのか - MUGENUP技術ブログ:http://mugenup-tech.hatenadiary.com/entry/2014/04/14/144759]] **並び替え [#j4148b2b] -orderを使って並び替えることができる Book.order(:created_at) -ASC、DESCの指定(全てのレコードを対象とする場合.all.orderにしてなくてもよいらしい)。 Book.order(created_at: :desc) Book.order(created_at: :asc) Book.order("created at DESC") Book.order("title DESC, created_at ASC") **個数制限 [#b70bbf84] -limitを使う Book.order(:created_at).limit(10) *更新 [#we2b3043] **条件にあうものをまとめて更新する。 [#e914b7f9] -whereしてからupdateではなく、whereしてからupdate_allする。[[【Rails DB更新、該当するデータを全て更新するには】 - Qiita:https://qiita.com/clbcl226/items/27ab4625999b06849c34]] User.where(age:25).update_all(hobby:'game') **updateとupdate_attributesの違いって? [#r080226f] -[[ActiveRecord の attribute 更新方法まとめ - Qiita:https://qiita.com/tyamagu2/items/8abd93bb7ab0424cf084]]によると同じらしい。 **オブジェクトの属性をコピーしたい [#q75db21c] -[[ruby - Creating a new object from another object's attributes in rails - Stack Overflow:https://stackoverflow.com/questions/48640075/creating-a-new-object-from-another-objects-attributes-in-rails]] -updateとattributesを使ってこうする? obj1.update(obj2.attributes.except('id', 'created_at', 'updated_at')) *保存 [#d162a6c4] **保存時に検証処理をバイパスする [#yb717c8a] -saveメソッドに"validate: false"を指定する。 @product.save(validate: false) *削除 [#ibe258c8] **全削除系 [#e98e0319] ***delete_allとdestroy_allの違い [#xa80c52a] -delete_allは関連を削除せずActiveRecordを介さないので高速。 -destroy_allは関連を削除するためにActiveRecordを介するので低速。 ***パラメータの指定 [#a8368bf7] -whereで検索してからdelete_all or destroy_allすればよい Manager.where(:manager_level => 5).destroy_all *Tips [#za8f7a18] **保存済みレコードかどうかの確認 [#a1b055eb] -new_record? 新規データの場合はtrue。 item.new_record? -persisted?保存済みの場合はtrue。 item.persisted? **複数のデータベースに接続する [#jdc8bc0c] -ActiveRecord::Baseを継承したクラスでestablish_connectionをそれぞれ設定する。 #pre{{ class OldPerson < ActiveRecord::Base self.table_name = 'person' self.inheritance_column = :old_type self.establish_connection(:adapter=>"mysql2",:host=>"localhost",:username=>$dbuser,:password=>$dbpasswd,:data\ base=>$olddbname) end class Person < ActiveRecord::Base self.inheritance_column = :old_type self.establish_connection(:adapter=>"mysql2",:host=>"localhost",:username=>$dbuser,:password=>$dbpasswd,:data\ base=>$newdbname) end }} **type列がエラーになる [#k2b54f44] -self.inheritance_column = :old_typeのようにして回避する #pre{{ class OldPerson < ActiveRecord::Base self.table_name = 'person' self.inheritance_column = :old_type end }} **大量のINSERTを早くする [#j333ff18] ***バックエンドのDB設定をチューニングする [#efef9ed0] -MySQLの場合my.cnfでinnodb_buffer_pool_sizeなどをいじる。 #pre{{ innodb_buffer_pool_size = 512M innodb_log_file_size = 128M }} ***transactionを使う [#ub5ccc1e] -saveなどをActiveRecord::Base.transaction do endで囲むとCOMMIT回数が減らせるので早くなる。 ***activerecord-import [#bd26a5c1] -[[zdennis/activerecord-import · GitHub:https://github.com/zdennis/activerecord-import]]を使う。MySQLの高速化した(圧縮された)INSERT文を生成してくれる。これが一番効果あった。 **SQLを表示する [#x2a1fe33] -loggerを使う。 #pre{{ require 'logger' ActiveRecord::Base.logger = Logger.new(STDOUT) }} *トラブルシューティング [#i49c62fd] **モデルクラスに実装したメソッド内でアトリビュートにアクセスしたらローカル変数とみなされる [#v4e39c96] -[[ruby on rails - Setting attribute from model without using self doesn't work - Stack Overflow:https://stackoverflow.com/questions/5369381/setting-attribute-from-model-without-using-self-doesnt-work]]にあるような例。例えばDeviceクラスのprepareメソッドでfull_nameを設定したいとする #pre{{ class Device < ActiveRecord::Base def prepare full_name = (!show_version || version.nil?)? name : name + " " + version.to_s end end }} -上の場合full_nameはローカル変数とみなされて、Deviceのfull_name属性に設定したとはみなされない。これを避けるためには次のようにしないといけない。 #pre{{ class Device < ActiveRecord::Base def prepare self.full_name = (!show_version || version.nil?)? name : name + " " + version.to_s end end }} -setterの場合は最初からローカル変数とみなされそこで終了するのに対し、getterの場合はローカル変数が存在しないとメソッドが検索される。 -結論。setterにはselfが必要。getterには不要。 ** 「[deprecated] I18n.enforce_available_locales will default to true in the future」というメッセージ [#gb82f542] -RailsではなくActiveRecord単体で使った時に表示されるようになった。スクリプトのどこかに以下を追加すればとりあえず回避できる。 I18n.enforce_available_locales = false