5

Ich muss einen Modellzähler automatisch erhöhen und seinen neuen Wert (von einem Sidekiq-Job verarbeitet) verwenden.Wert des atomaren Zählers (Inkrement) mit Rails und Postgres erhalten

Im Moment benutze ich

Group.increment_counter :tasks_count, @task.id 

in meinem Modell, das den Zähler atomar erhöht.

Aber Ich brauche auch seinen neuen Wert, um eine Benachrichtigung zu senden, wenn der Zähler z. der Wert 50. Irgendwelche Ideen? Den Tisch/die Reihe sperren oder gibt es einen einfacheren Weg?

Bearbeiten/SOLUTION

Basierend auf mu ist zu kurz ‚s Antwort und update_counters Methode des Rails, ich eine Instanz Methode implementiert (mit PostgreSQL getestet).

def self.increment_counter_and_return_value(counter_name, id) 
    quoted_column = connection.quote_column_name(counter_name) 
    quoted_table = connection.quote_table_name(table_name) 
    quoted_primary_key = connection.quote_column_name(primary_key) 
    quoted_primary_key_value = connection.quote(id) 

    sql = "UPDATE #{quoted_table} SET #{quoted_column} = COALESCE(#{quoted_column}, 0) + 1 WHERE #{quoted_table}.#{quoted_primary_key} = #{quoted_primary_key_value} RETURNING #{quoted_column}" 
    connection.select_value(sql).to_i 
end 

verwenden Sie es wie:

Group.increment_counter_and_return_value(:tasks_count, @task.id) 

Es nutzt RETURNING den neuen Wert innerhalb derselben Abfrage zu holen.

Antwort

5

Ihre Group.increment_counter Anruf sendet SQL wie diese an die Datenbank:

update groups 
set tasks_count = coalesce(tasks_counter, 0) + 1 
where id = X 

wo X@task.id ist. Der SQL-Weg, um den neuen tasks_counter Wert zu erhalten, ist eine RETURNING-Klausel enthalten:

update groups 
set tasks_count = coalesce(tasks_counter, 0) + 1 
where id = X 
returning tasks_count 

Ich weiß nicht, von jeder geeigneten Railsy Weise aber, dass SQL auf die Datenbank zu erhalten. Der üblicher Rails Ansatz wäre, entweder eine Reihe von Sperren zu tun und lädt @task oder die Verriegelung überspringen und das Beste hoffen:

Group.increment_counter :tasks_count, @task.id 
@task.reload 
# and now look at @task.tasks_count to get the new value 

Sie können RüCKKEHR wie dies obwohl verwenden:

new_count = Group.connection.execute(%Q{ 
    update groups 
    set tasks_count = coalesce(tasks_counter, 0) + 1 
    where id = #{Group.connection.quote(@task.id)} 
    returning tasks_count 
}).first['tasks_count'].to_i 

Sie‘ Ich möchte wahrscheinlich dieses Chaos hinter einer Methode auf Group verstecken, so dass Sie Dinge wie sagen könnten:

n = Group.increment_tasks_count_for(@task) 
# or 
n = @task.increment_tasks_count 
+0

Vielen Dank für mich auf diese. Ich habe meine Frage mit einer Instanzmethode aktualisiert, die auf Ihrer Antwort basiert. – tbuehl