Rails on me :)
2010년 3월 25일 목요일
  Ruby on Rails : Active Record Validation 메세지 한글화 하기

Rails 가 제공하는 Model단의 validation 기능과 사용자 페이지(View)에 메세지를 보여주는 기능은 무척 유용하다. 만약, 가격 필드에 문자값을 넣으면 validates_numericality_of 메서드를 이용하여 검증하면 다음과 같은 메세지를 뿌려준다.


class Order < ActiveRecord::Base  
  validates_numericality_of :price
end
--------------------------------------------------------
"Price is not a number" <== view page 에서 보여지는 메세지.

위 메세지를 한글화 하려면 옵션을 주면 다음과 같이 보이게 할수 있다.



class Order < ActiveRecord::Base
  validates_numericality_of :price, :message => "항목은 숫자만 입력가능 합니다."
end

"Price 항목은 숫자만 입력가능 합니다."

문제는 저 Price 이다. 이는 속성의 이름이 default 로 문장의 맨앞에 나와있으며, 이를 바꿀 방법이없다. 그렇기에 아쉽지만 좀더 사용자 친화적인 메세지로 바꾸려면 validates_numericality_of 메서드를 포기하고 직접 만드는 수밖에 없다. 다음처럼 말이다.


class Order < ActiveRecord::Base
  validate :price_must_be_a_number

  protected

  def price_must_be_a_number
    begin
      Kernel.Float(price)
    rescue ArgumentError, TypeError
      errors.add('price', '항목은 숫자만 입력해주세요.')
    end
  end
end

Kernel.Float 는 값이 float 타입인지를 판별하는 여러 방법중 하나이다. 이 방법이 아닌 다르게 체크해도 상관없다. 한데 문제가 있다. 사용자가 숫자가 아닌 문자열을 입력했을 때, price_must_be_a_number 메서드의 price 속성에 떨어지는값이 0.0인것이다 ! Rails 자체적으로 숫자입력이 필요한곳에 문자입력을 했을때 자동으로 0.0으로바꾸는것이다. 그렇기에 사용자가 문자를 입력해도 위의 validation이 통과되버리게된다.

해결방법을 찾아 며칠 전전긍긍한 끝에 Rails API 에서 해답을 얻을 수 있었다 !
http://api.rubyonrails.org/classes/ActiveRecord/Base.html 에 문제를 푸는 열쇠가 담겨있다. 다음과 같은 내용이 있다.


Accessing attributes before they have been typecasted

Sometimes you want to be able to read the raw attribute data without havingthe column-determined typecast run its course first. That can be done by using the_before_type_cast accessors that all attributeshave. For example, if your Account model has a balance attribute,you can call account.balance_before_type_castoraccount.id_before_type_cast.
This is especially useful in validation situations where the user mightsupply a string for an integer field and you want to display the originalstring back in an error message. Accessing the attribute normally wouldtypecast the string to 0, which isn‘t what you want.

_before_type_cast 를 통해, 케스팅되기 전의 값을 알수 있는 것이다! 이제 다음과 같이 validation 체크가 가능하다.


validate :price_must_be_a_number

protected

def price_must_be_a_number
  begin
    Kernel.Float(price_before_type_cast)
  rescue ArgumentError, TypeError
    errors.add('price', '가격항목에는 숫자만 입력해주세요.')
  end
end

"Price 가격항목에는 숫자만 입력해주세요."

자, 이제 한글 validation 메세지를 보여주는 마지막 단계이다. errors.add 함수에는 세개의 인자값을 받는데, 다음처럼 마지막 인자인 option 설정을 통해 메세지에서 Price 부분을 제거할 수 있다.


validate :price_must_be_a_number

protected

def price_must_be_a_number

  begin
    Kernel.Float(price_before_type_cast)
  rescue ArgumentError, TypeError
    errors.add('price', '가격항목에는 숫자만 입력해주세요.', {:attribute => '' })
  end
end

"가격항목에는 숫자만 입력해주세요."

위의 방식을 응용하면 모든 입력폼에 관한 한글 validation 메세지를 사용자들에게 제공해줄 수 있게 된다. :)

라벨: , ,

 
댓글: 댓글 쓰기

에 가입 댓글 [Atom]





<< 홈
with ruby core and CGIs

내 사진
이름:
위치: Seoul, South Korea

모니터 앞에서 싸구려 커피를 마시며

아카이브
3월 2010 / 4월 2010 / 5월 2010 / 6월 2010 / 7월 2010 / 11월 2010 / 12월 2011 /


Powered by Blogger

에 가입
글 [Atom]