0

次のモデル/関連付けのセットアップがあります。

class Contact < ActiveRecord::Base
  has_and_belongs_to_many :assigned_users, class_name: 'User'

  def auto_assign_team_member(project)
    team = project.teams(true).order('last_assigned_contact_at ASC').first
    if team && (user = team.user)
      self.assigned_users << user
      team.update_attribute(:last_assigned_contact_at, Time.now)
    end
  end
end

class Team < ActiveRecord::Base
  belongs_to :user
  belongs_to :project
end

class User < ActiveRecord::Base
  has_many :teams
  has_many :projects, through: :teams
  has_and_belongs_to_many :assigned_contacts, class_name: 'Contact'
end

class Project < ActiveRecord::Base
  has_many :teams
  has_many :users, through: :teams
end

Contactメソッドをトラバースして実行するインスタンスのコレクションもありますauto_assign_team_member。私の問題は、ほとんどすべての実行teamで lvar が同じチームを返すことです。テーブルには 2 つのレコードがあり、チーム メンバーをアソシエーションに均等に分配することを意図しています。teamsContact#assigned_users

コンソールでは、次のように動作します。

project.teams(true).order('last_assigned_contact_at ASC').first #=> Team(user_id: 1)
project.teams(true).order('last_assigned_contact_at ASC').first.update_attribute(:last_assigned_contact_at, Time.now)
project.teams(true).order('last_assigned_contact_at ASC').first #=> Team(user_id: 2)

ここでどこが間違っているのか分かりますか?

編集誰かが興味を持っている場合は、これを再現する小さなアプリケーションを作成しましたhttps://github.com/injekt/teamr

簡単に実行rake db:seedしてテスト データを実行できます。出力は、毎回同じユーザーを表示するのではなく、各ユーザーに均等に分散する必要があります。

EDIT 結局のところupdate_attribute(:last_assigned_contact_at, 'now()')代わりに実行するとうまくいきます。では、Rails は何かファンキーなことを内部で行っているのでしょうか? これには高い精度が必要だと思いますが、レールはそれを処理できると思います

4

1 に答える 1

2

問題は Rails が任意の Time オブジェクトから usec を四捨五入しているようです。おそらく、PostgreSQL だけが「タイムゾーンなしのタイムスタンプ」データ型でそのような精度を実際にサポートしているためです。

タイムスタンプ属性は、他の属性とは異なる方法で処理されます。このモジュールでは、それらのカスタム セッターが定義されています: https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb

時間オブジェクトは、値を比較して割り当てる前に丸められますhttps://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb#L46

奇妙な問題は、ビルトイン Rails タイムスタンプ カラムの精度がそこにあることです。これは、組み込みのタイムスタンプが を呼び出すことによってカスタム セッターをバイパスするためwrite_attribute(:column, value)です。

したがって、修正はteam.update_attribute呼び出しの代わりにこれを行うことです

team.send(:write_attribute, :last_assigned_contact_at, Time.current)
team.save

これにより、カスタム セッター ロジック全体が効果的にバイパスされ、組み込みのタイムスタンプ更新を処理するのと同じように値が処理されます。

于 2012-12-18T15:43:10.417 に答える