Ruby on rails Rails协会有一项最新记录

Ruby on rails Rails协会有一项最新记录,ruby-on-rails,activerecord,associations,Ruby On Rails,Activerecord,Associations,我有以下型号: 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',

我有以下型号:

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

其中,当前修订是最近创建的修订。是否可以将当前版本转换为关联,以便执行类似Section.wherecurrent\u revision.parent\u Section\u id='1'的查询?或者我应该将当前修订列添加到我的数据库中,而不是尝试虚拟地或通过关联创建它?

您可以将其更改为关联,但通常情况下,在查询中使用has\u one或Bowns\u to association排序时,总是会被错误地解释。在你的问题中,当你把它变成一个协会,那将是

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

因此,我建议您添加一个当前的\u修订\u id。

我知道您希望获得每个节的最后一个修订版都有一个父节\u id=1的节

我有一个类似的情况,首先,这是SQL,请将类别视为您的部分,将帖子视为修订版,将用户\u id视为家长\u部分\u 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)")
这是有效的,它是丑陋的,我认为最好的方法是削减查询,但如果你有太多的部分,这将是一个问题,而循环通过他们;您还可以将此查询放入静态方法中,而且,您的第一个想法是,在sections表中设置一个revision_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查询相同,但我在HAVE中更改了查询以进行优化;当心这群人;includes使其在大型数据集中成为最佳,很抱歉,我找不到与has_one建立关系的方法,但我同意这一点,但也要重新考虑您在开始时提到的字段。

要获得has_许多的最后一个,您需要做一些类似于@jvnill的事情,除了向关联添加具有排序的作用域外:

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

这将确保您从数据库中获得最新版本。

正如@jvnill所提到的,使用order的解决方案在进行更大的查询时停止工作,因为order的范围是完整查询,而不仅仅是关联

这里的解决方案需要精确的SQL:

有一个:当前修订,->{不存在的地方从章节修订sr中选择1,其中sr.id>章节修订.id和sr.section\U id=章节修订.section\U id限制1},类别名称:'SectionRevision',外键::章节修订id 如果您的数据库支持DISTINCT ON


漂亮,这正是我想要的!如果对section\u revisions.section\u id有空约束,请确保不要使用has\u one helper record.create\u current\u revision或record.build\u current\u revision,否则将无法删除现有关联的当前\u修订。记录的外键设置为nil后无法保存。相反,总是使用record.section_revisions.create,这将是新的当前_修订说明,对于Rails 4+,您需要做一件事:当前_修订,lambda{ordercreated_at DESC},类名:'SectionRevision',foreign_key::section_id。我花了一些时间思考,但我找到了一种100%有效的方法。感谢分享您的解决方案并指出其缺陷,它为我节省了很多时间和错误!我很困惑@jvnill指出,当has_one关联加入时,订单部分会被删除,而您的答案似乎没有改变。我的答案实际上是相同的,只是它是旧的rails 3.2格式。应该将“created_at DESC”的顺序移到开头,以便更容易看到。我想指出的是,当您尝试将其与不同的查询组合时,必须注意注意注意事项。有关示例,请参见其中的第二个代码。
class Section < ApplicationRecord
  has_one :current_revision, -> { merge(SectionRevision.latest_by_section) }, class_name: "SectionRevision", inverse_of: :section
end
class SectionRevision < ApplicationRecord
  belongs_to: :section
  scope :latest_by_section, -> do
    query = arel_table
      .project(Arel.star)
      .distinct_on(arel_table[:section_id])
      .order(arel_table[:section_id].asc, arel_table[:created_at].desc)
    revisions = Arel::Nodes::TableAlias.new(
      Arel.sql(format("(%s)", query.to_sql)), arel_table.name
    )
    from(revisions)
  end
end