ActiveRecordハック

今日は、Ruby on Railsアプリケーションの開発プロセスで遭遇した、または他の人のブログで見つかった、必ずしも明らかではない一連のActive Recordの機能を共有します。







update_attributesを使用する場合の検証バイパス



標準のupdate_attributesメソッドには検証を回避するためのキーがないため、assign_attributesを使用してからsaveを行う必要があります。



@user = User.find(params[:id]) @user.assign_attributes(:name, "") @user.save(validate: false)
      
      







もちろん-非常に頻繁にこの方法に頼らない方が良いです:)



2つのばらばらのコレクションに分割



オブジェクトのサンプルを2つのばらばらのコレクションに分割する問題が発生する場合があります。 これは、このスコープの使用を使用して実行できます。



 Article < ActiveRecord::Base scope :unchecked, where(:checked => false) #or this, apologies for somewhat unefficient, but you already seem to have several queries scope :unchecked2, lambda { |checked| where(["id not in (?)", checked.pluck(:id)]) } end
      
      







それに応じて、両方のコレクションへのアクセスは、次を使用して取得できます。



 Article.unchecked Article.unchecked2(@unchecked_articles)
      
      







摘む



前の例では、pluckメソッドを使用しました。 きっとあなたはそれぞれ



 Article.all.select(:title).map(&:title)
      
      







または



 Article.all.map(&:title)
      
      







だから-プラックはそれを簡単にします



 Article.all.pluck(:title)
      
      







基本クラスへのアクセス



1つのプロジェクトに取り組む過程で、モデルクラスの大規模なネストとルートクラスに到達する必要性に出会いました。 クラスは次のようになりました。



 class Art < ActiveRecord::Base end class Picture < Art end class PlainPicture < Picture end
      
      







PlainPictureからArtを取得するには、becomesメソッドを使用できます。



 @plain_pictures = PlainPicture.all @plain_pictures.map { |i| if i.class < Art then i.becomes(Art) else i end }.each do |pp| #do something with Art end
      
      







first_or_createおよびfirst_or_initialize



もう1つの優れた方法は、first_or_createです。 彼が何をしているのかは名前から明らかであり、どのように使用できるかを見てみましょう。



 Art.where(name: "Black square").first_or_create
      
      







ブロックデザインでも使用できます。



 Art.where(name: "Black square").first_or_create do |art| art.author = "Malevich" end
      
      







そして、保存したくない場合-たとえば、この方法でfirst_or_initializeを使用できます



 @art = Art.where(name: "Black square").first_or_initialize
      
      







有効範囲なし



スコープ付きとなしの2つのすばらしい方法に注意してください。 どのように動作するのか例を示しますが、rails3とrails4では振る舞いが異なるため、振る舞いを分離する必要があることに注意してください。



 def filter(filter_name) case filter_name when :all scoped when :published where(:published => true) when :unpublished where(:published => false) else none end end
      
      







に渡されたときにメソッドがどのように動作するか:公開済みと未公開ここでRailsバージョンに違いはありません。



rails3の場合、この例でscopedを使用すると、複雑な複合クエリに使用できる匿名スコープを作成できます。 rails4で適用しようとすると、メソッドが非推奨になり、代わりにModel.allを使用するよう提案されているというメッセージが表示されます。 rails3の場合、Model.allは期待されるActiveRecord :: Relationではなく、Arrayを返します。



何もない状況は、まったく反対のスコープに似ています:)このメソッドは空のActiveRecord :: Relationを返しますが、rails4でのみ機能します。 ゼロの結果を返す必要がある場合に必要ですrails3で使用するには、次のような回避策があります。



 scope :none, where(:id => nil).where("id IS NOT ?", nil)
      
      







またはそのようなもの(たとえば、初期化子)



 class ActiveRecord::Base def self.none where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil))) end end
      
      







find_each



find_eachメソッドは、データベースから大量のレコードを処理するのに非常に便利です。 もちろん、タイプのサンプルを作成できます



 Article.where(published: true).each do |article| #do something end
      
      







ただし、この場合、サンプル全体をメモリに保存する必要があります。これは、大量のデータの場合、非常に収益性が低くなります。 この場合、このアプローチを使用する方が適切です。



 Article.where(published: true).find_each do |article| #do something end
      
      







少量のサンプル(デフォルトでは一度に1000個のオブジェクト)がデータを処理します。



to_sqlおよびExplain



リクエストの仕組みを理解するのに役立つ2つの方法。



 Art.joins(:user).to_sql
      
      







データベースを照会するためにアプリケーションが作成するsql照会を返します。



 Art.joins(:user).explain
      
      







リクエストに応じて技術情報(おおよその時間、サンプルサイズ、その他のデータ)が表示されます。



スコーピング



このメソッドを使用すると、たとえば、選択範囲内で選択を行うことができます。



 Article.where(published: true).scoping do Article.first end
      
      







のようなリクエストをする



 SELECT * FROM articles WHERE published = true LIMIT 1
      
      







併合する



複数のサンプルを横断できる別の興味深い方法。 例えば



 class Account < ActiveRecord::Base # ... # Returns all the accounts that have unread messages. def self.with_unread_messages joins(:messages).merge( Message.unread ) end end
      
      







未読メッセージがあるすべてのアカウントを選択できます。



All Articles