2010-07-04 4 views
0

내 모델의 after_update 콜백에서 백분율을 다시 계산하려고합니다.after_update 콜백 문제

def update_percentages 
    if self.likes_changed? or self.dislikes_changed? 
     total = self.likes + self.dislikes 

     self.likes_percent = (self.likes/total) * 100 
     self.dislikes_percent = (self.dislikes/total) * 100 
     self.save 
    end 
    end 

이것은 작동하지 않습니다. 백분율은 항상 100이나 0으로 나오며 모든 것을 완전히 망칩니다.

어디로 빠지나요? 나는 self.likes와 self.dislikes가 올바르게 증가하고 있음을 보장한다.

답변

5

문제점

당신이 정수 (일명 정수 나누기)에 의해 정수를 나눌 때, 루비 등 대부분의 프로그래밍 언어는, 가정 당신은 당신의 결과를 Integer로 원한다. 숫자의 낮은 수준 표현에서는 정수가 소수점 이하의 숫자와 매우 다르기 때문에 정수가있는 부분은 보다 빠르기 때문에 대부분 역사에 기인합니다. 그래서 비율, 0과 1 사이의 숫자는 그 진수가 잘립니다있다, 그래서 100을 곱한 때 0 또는 1을, 0 또는 100

일반적인 솔루션

을하게되고 만약의 나누기의 숫자가 정수가 아닌 경우 정수 나누기가 수행되지 않습니다. 대안은 소수점이있는 숫자입니다. 이런 종류의 숫자 유형이 있지만 일반적으로 부동 소수점 수라고하며 루비에서는 가장 일반적인 부동 소수점 수는 Float 클래스입니다. 레일 '모델에서

1.0.class.ancestors 
    # => [Float, Precision, Numeric, Comparable, Object, Kernel] 

1.class.ancestors 
    # => [Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel] 

는 수레는 루비의 BigDecimal 클래스 루비 Float 클래스 및 십진수로 표시됩니다. 차이점은 BigDecimals가 훨씬 정확하다는 것입니다 (즉, 돈을 위해 사용될 수 있음).

일반적으로 숫자를 실수로 "typecaste"할 수 있습니다. 즉, 더 이상 정수 나누기를 수행하지 않습니다. 그런 다음 필요할 경우 계산 후 다시 정수로 변환 할 수 있습니다.

x = 20    # => 20 
y = 30    # => 30 
y.to_f    # => 30.0 

x.class    # => Fixnum 
y.class    # => Fixnum 
y.to_f.class  # => Float 

20/30    # => 0 
20/30.0   # => 0.666666666666667 

x/y    # => 0 
x/y.to_f   # => 0.666666666666667 

(x/y.to_f).round # => 1 

솔루션을 당신은 당신의 경우

, 당신이 분할 전에 100에 의해 번식하는 것이 작업을 수행하는 가장 쉬운 방법을 생각하면 (즉, 42 42 %)을 정수 결과를하고자하는 가정. 이것은 소수점을 오른쪽으로 멀리 밀어내어 부서 앞에 올리면 숫자가 정확할만큼 정확하다는 것을 의미합니다.

before_save :update_percentages 
def update_percentages 
    total = likes + dislikes 
    self.likes_percent  = 100 * likes/total 
    self.dislikes_percent = 100 * dislikes/total 
end 

주 :

  • 난 당신은 로컬 변수를 만드는 것을 명확하게하는 임무를해야하고, 로컬 변수가 때 오히려 메소드를 호출 할 것을 명확하게 암시 적 self을 제거 변수를 참조하는 것보다
  • egarcia에서 제안한대로 저장하기 전에 콜백으로 이동했습니다. (내가 before_ 을 저장하고을 저장했는데 이유는 모르겠지만 업데이트에서이 백분율을 계산해야하는 이유는 모르지만 창조하다 먹었고, 숫자가 정확하다는 것을 확인한 후에 일어날 것 같아요. 즉, 범위 내에서, 정수 또는 소수점 이하에서
  • 저장하기 전에 완료되었으므로 코드에서 save 호출을 제거하고, 이미 일어날 것입니다.
  • 콜백에 명시 적으로 저장하지 않기 때문에 무한 루프가 발생하지 않으므로 숫자가 업데이트되었는지 확인할 필요가 없습니다. 저장할 때마다 백분율을 계산합니다.
1

이 문제가 유일한 문제인지는 모르겠지만, 객체를 저장 한 후에 after_update이 호출됩니다.

전에 before_update 또는 before_validate 대신 update_percentages을 변경해보십시오. 또한 self.save 행을 제거하십시오. 해당 콜백 중 하나를 사용하면 나중에 자동으로 호출됩니다.

+0

고마워요, 그 말이 낫습니다. –

2

좋아요/싫어요는 정수 값이고 정수/정수 = 정수입니다.

두 가지 중 하나를 수행하거나 플로팅으로 변환하거나 작업 순서를 변경할 수 있습니다.

self.likes_percent = (self.likes.to_f/total.to_f) * 100 

또는 유지하기 위해 모든 정수

self.likes_percent = (self.likes * 100)/total