21

私は次のモデルを持っています:

class Section < ActiveRecord::Base
  belongs_to :page
  has_many :revisions, :class_name => 'SectionRevision', :foreign_key => 'section_id'
  has_many :references

  has_many :revisions, :class_name => 'SectionRevision', 
                       :foreign_key => 'section_id'

  delegate :position, to: :current_revision

  def current_revision
    self.revisions.order('created_at DESC').first
  end
end

current_revision最近作成された はどこにありますかrevisioncurrent_revisionのようなクエリを実行できるように、関連付けに変えることは可能Section.where("current_revision.parent_section_id = '1'")ですか? current_revisionまたは、仮想的に、または関連付けを介して列を作成するのではなく、データベースに列を追加する必要がありますか?

4

5 に答える 5

37

has_many で最後を取得するには、@jvnill と同様のことを行う必要がありますが、関連付けに順序付きのスコープを追加することを除きます。

has_one :current_revision, -> { order created_at: :desc }, 
  class_name: 'SectionRevision', foreign_key: :section_id

これにより、データベースから最新のリビジョンを取得できます。

于 2014-08-07T03:59:27.113 に答える
21

アソシエーションに変更することはできますが、通常、has_oneまたはbelongs_toアソシエーションの順序付けは、クエリで使用すると常に間違って解釈されます。あなたの質問では、それを関連付けにすると、

has_one :current_revision, class_name: 'SectionRevision', foreign_key: :section_id, order: 'created_at DESC'

これに関する問題は、これを他のクエリと組み合わせようとすると、通常、間違ったレコードが返されることです。

>> record.current_revision
   # gives you the last revision
>> record.joins(:current_revision).where(section_revisions: { id: 1 })
   # searches for the revision where the id is 1 ordered by created_at DESC

そのため、代わりに a を追加することをお勧めしますcurrent_revision_id

于 2013-04-05T01:31:32.693 に答える
1

各セクションの最後のリビジョンがparent_section_id = 1; であるセクションを取得したいことを理解しています。

私は同様の状況を抱えています。まず、これはSQLです(カテゴリをセクション、投稿をリビジョン、user_idをparent_section_idと考えてください-必要に応じてコードを移動しない場合は申し訳ありませんが、行かなければなりません):

SELECT categories.*, MAX(posts.id) as M
FROM `categories` 
INNER JOIN `posts` 
ON `posts`.`category_id` = `categories`.`id` 
WHERE `posts`.`user_id` = 1
GROUP BY posts.user_id
having M = (select id from posts where category_id=categories.id order by id desc limit 1)

Rails でのクエリは次のとおりです。

Category.select("categories.*, MAX(posts.id) as M").joins(:posts).where(:posts => {:user_id => 1}).group("posts.user_id").having("M = (select id from posts where category_id=categories.id order by id desc limit 1)")

これは機能しますが、醜いです。最善の方法はクエリを「カット」することだと思いますが、セクションが多すぎると、ループ中に問題が発生します。このクエリを静的メソッドに配置することもできます。また、最初のアイデアとして、セクション テーブル内に rev_id を含めると、クエリを最適化するのに役立ちますが、正規化が失われます (必要な場合もあります)。そのセクションの新しいリビジョンが作成されたときにこのフィールドを更新します (したがって、巨大なデータベースで多くのリビジョンを作成する場合、遅いサーバーを使用している場合は悪い考えになるかもしれません...)

更新 私は戻ってきました、私はいくつかのテストを行っていました、そしてこれをチェックしてください:

def last_revision
    revisions.last
end

def self.last_sections_for(parent_section_id)
  ids = Section.includes(:revisions).collect{ |c| c.last_revision.id rescue nil }.delete_if {|x| x == nil}

  Section.select("sections.*, MAX(revisions.id) as M")
         .joins(:revisions)
         .where(:revisions => {:parent_section_id => parent_section_id})
         .group("revisions.parent_section_id")
         .having("M IN (?)", ids)
end

私はこのクエリを作成し、自分のテーブルで作業しました (params に適切な名前を付けたことを願っています。これは以前と同じ Rails クエリですが、最適化のためにクエリを変更しています); グループに気をつけてください。インクルードにより、大規模なデータセットで最適になります。申し訳ありませんが、has_one との関係を作成する方法が見つかりませんでしたが、これを使用しますが、最初に言及したフィールドも再検討してください。

于 2013-04-05T01:35:42.650 に答える