2015-05-06 11 views
5

Potrzebuję atomowo zwiększać licznik modelu i używać jego nowej wartości (przetwarzane przez zadanie Sidekiq).Uzyskaj wartość licznika atomowego (przyrost) z szynami i Postgresem

Obecnie używam

Group.increment_counter :tasks_count, @task.id 

w moim modelu, który niepodzielnie zwiększa licznik.

Ale potrzebuję również jego nowej wartości do wysłania powiadomienia, jeśli licznik ma np. wartość 50. Jakieś pomysły? Blokowanie stołu/rzędu czy jest łatwiejszy sposób?

Edycja/ROZWIĄZANIE

podstawie MU jest zbyt krótki „s odpowiedź i update_counters metoda szyn, w I wdrożone metodę instancji (testowane z PostgreSQL).

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 

używać go jak:

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

Wykorzystuje RETURNING aby pobrać nową wartość w obrębie tego samego zapytania.

Odpowiedz

5

Twój Group.increment_counter wezwanie wysyła tak SQL do bazy danych:

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

gdzie X jest @task.id. Sposób SQL, aby uzyskać nową wartość tasks_counter ma obejmować powrocie klauzuli:

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

nie wiem o dowolnym dogodnym Railsy sposób, aby ta SQL do bazy danych chociaż. Zazwyczaj podejście Rails byłoby też zrobić kilka blokowania i przeładować @task lub ominąć blokadę i nadzieję na najlepsze:

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

Można użyć ZWROT tak jakby:

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 

You” Prawdopodobnie chcesz ukryć ten bałagan za metodą pod numerem Group, dzięki czemu możesz powiedzieć:

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

Dziękuję za skierowanie mnie do tego. Zaktualizowałem swoje pytanie za pomocą metody instancji opartej na Twojej odpowiedzi. – tbuehl