0

Railsモデルのスコープ(またはself.func_name)内で配列関数(具体的には「keep_if」と「include?」)を使用しようとしていますが、それを機能させる方法がわかりません。「where」は「set.where」を意味しているように見えるので、それは可能だと思っていたので、「set.keep_if」は理にかなっています。

私はドキュメントのテーブル(または、ドキュメントのメタデータ)を持っています。ここで、各ドキュメントは、リンクされたテーブル内にそれ自体の異なるバージョンを持っています。doc.next_versionおよびdoc.prior_version。ドキュメントにリンクされている人のテーブルがあります(別のテーブル「作成者」を介して)。したがって、person.documentsは、その人が作業した各ドキュメントのすべてのバージョンのリストです。/ every /バージョンではなく、各自が作業したドキュメントの最初または最後のバージョンを取得したいと思います。

コードに関する私の推測は次のとおりです。

class Document < ActiveRecorrd::Base

  has_many :authors

  belongs_to :next_version, :class_name => 'Document'
  has_one :prior_version, :class_name => 'Document'
  #document.document_id is the ID of the prior version of this document

  scope :last!, lambda{ keep_if{|d| (d.next_version.nil?)||(! include?(d.next_version))}}
  # Keep a doc if it either has no next_version (and is thus the last version in 
  # the database), or it's next version isn't in this list.
end

class Person < ActiveRecord::Base
  has_many :authors
  has_many :documents, :through => :authors
end

class Author > ActiveRecord::Base
  belongs_to :person
  belongs_to :document
end

#Usage Example
documents = Person.find(id).documents.last!
published = documents.keep_if{|d| d.published}
success_rate = published.size / documents.size
# etc

に変換してみましたself.first!が、役に立ちませんでした。(人が請求書のバージョンをスキップした場合、このメソッドはスキップせず、そのドキュメントの2つのバージョンを返すことを理解しています)

私は、「スコープ」内で何が起こっているのか、そしてそれが完全に異なる方法を使用しているとしても、私がやろうとしていることをどのように行うのかをもっと知りたいと思っています。

プレーンテキストからメタデータを自分で生成していますが、ほとんどすべてを完全に制御できます。したがって、新しいメタデータフィールドを追加することはできますが、それに伴うすべての作業を行う必要があります。

4

2 に答える 2

1

どうしたの:

scopesクエリの名前付きスニペットのように機能します。それらを使用してクエリを作成すると、ActiveRecordは結果の複合クエリを遅延評価します。したがって、スコープとクラスメソッドの観点からは、他のコードの観点からは配列のように機能しますが、配列でPerson.first.documents はありません-Person.first.documents.keep_if{...}

回避策は非常に簡単です。ARELにクエリを評価して配列に変換するように求めるだけです。

def self.last!
  all.keep_if{...}  
 #^^^ It's the "all" that does it
end

この場合の私の実際のロジックは(d.next_version.nil?)||(! all.include?(d.next_version))機能しないことに注意してください。理由はまだわかりません。

編集:これは「belongs_to:next_version ...」と関係があり、def next_version実際に問題を解決していなくても、回避策によって問題が機能します。

編集2:これを今のところ答えとして受け入れるつもりです。なぜなら、それは私が望む方法で使用コードを使ってやりたいことを得るからですが、IMO / AFAIKはあまりRailsソリューションではありません-したがって、より良いもの、私は完全にその船にジャンプします。

于 2012-09-18T20:50:53.587 に答える
0

ActiveRecordには、last!オーバーライドしているメソッドがすでにあります。これは良い考えではないと思います。代わりに、ロジックを別の方法で表現する方がよいと思います。

class Document < ActiveRecord::Base

    def self.published_documents
        keep_if do |d|
            (d.next_version.nil? || !include?(d.next_version)) && d.published
        end
    end
end

これにより、IMOの後にある基本的なロジックが実装されます。

さらに一歩進んで、Personの公開されたドキュメントに本当に興味があるので、このメソッドもPersonクラスに移動すると思います。

class Person < ActiveRecord::Base

    def published_documents
        documents.keep_if do |d|
            (d.next_version.nil? || !documents.include?(d.next_version)) && d.published
        end
    end
end

その場合、使用法は次のようになります。

Person.find(id).published_documents
于 2012-09-13T02:10:29.143 に答える